In my application we have the following architecture:
We want to use Hibernate as ORM framework instead of JDBC in DAO layer. I want to use Spring ORM feature for integrating Hibernate in DAO layer. Now, challenges that we are facing:
DAO layer classes are stateless EJB classes. So,to use Spring DI inside EJB classes, I have to go for an interceptor as follows:
@Stateless(mappedName = "myAppDao")
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyAppDaoImpl implements MyAppDaoRemote {
@Autowired
private SessionFactory sessionFactory;
@Override
public void getSession() {
if(sessionFactory!=null){
Session session = null;
try{
session = sessionFactory.getCurrentSession();
}catch (Exception e) {
session = sessionFactory.openSession();
System.out.println("Exception:"+e.getMessage());
}
}
With sessionFactory.getCurrentSession()
I am getting this exception:
Exception:Could not obtain transaction-synchronized Session for current thread.
The reason behind this I am not able to use Spring transaction at Service layer since I have EJB classes in my service layer.
Moreover I don't want to use sessionFactory.openSession()
as in that case I would have to manually close the session.
These are my Spring configuration files:
1) beanRefContext.xml -> Used by Interceptors
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<bean id="businessBeanFctory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="classpath*:daoConfig.xml" />
</bean>
</beans>
2) daoConfig.xml -> Hibernate Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.myapp.model"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyAppDS" expected-type="javax.sql.DataSource"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
I know that there is no point in using EJB along with Spring since they are alternate to each other.But due to some restriction at project level I can't remove EJB for the time being.
So, is there any solution by which we can get the Hibernate current session inside an EJB class through Spring?
If you're using JBossAS/WildFly then you just need:
@Stateless(mappedName = "myAppDao")
public class MyAppDaoImpl implements MyAppDaoRemote {
@PersistenceContext
private Session session;
public void someDaoMethod(YourEntity e) {
// use session directly
// Transactions are automatically managed by the EJB container
// because that's one of EJB's raison d'être
}
}
Ensure that your (traditional) Hibernate configuration specifies JTA transactions.
See the WildFly JPA Reference Guide for more information.
If you're not using one of these JavaEE implementations then you can still use the Spring configuration that you have, but remember to include:
<property name="jtaTransactionManager" value="transactionManager"/>
in your sessionFactory
bean.
Additionally, if you're using WebLogic or WebSphere you may need to specify platform dependent JTA transaction managers for these servers, such as WebLogicJtaTransactionManager
or org.springframework.transaction.jta.WebSphereUowTransactionManager
.