Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: Spring + Hibernate + CMT + Single Session per Transaction
PostPosted: Wed Mar 31, 2004 7:29 pm 
Beginner
Beginner

Joined: Wed Feb 25, 2004 6:23 pm
Posts: 39
We are creating an enterprise application and are required to use stateless session beans and container managed transactions. We will be using Hibernate for persistence. We will also be using Spring to make our life easier. I like that Spring can help me avoid the whole installing-Hibernate-using-JCA thing, but I'm having trouble with Session management and CMT. I'm using the HibernateInterceptor so that Spring can manage my Sessions for me (my DAOs extend HibernateDaoSupport), but it seems that without using Spring Managed Transactions, I get a new Session each time I call getSession() in HibernateDaoSupport. I've been searching around in various forums, and have found only confusing or incomplete answers (since there have been different answers to this problem during different phases of Spring's development).
So, with the new 1.0 release, is it possible to use Spring to manage Hibernate Sessions from behind a SLSB facade so that you get one session per transaction while using CMT? If so, how?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 02, 2004 9:29 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
Unfortunately, standard JTA/EJB does not allow for registering additional resources with transactions. So you need to use Spring's JtaTransactionManager within the EJB, i.e. additionally do programmatic or declarative transaction demarcation via Spring. In such a scenario, JtaTransactionManager will simply participate in the existing JTA/EJB transaction but additionally manage a scoped Hibernate Session within the "nested" transaction that it manages. You have to use this level of Spring transaction management to get the desired behavior.

Note that when using JtaTransactionManager here, the Hibernate Session will be closed at the end of the Spring-managed transaction: Strictly speaking, Hibernate's cache callbacks will be applied too early then, as the surrounding JTA/EJB transaction has not committed yet. To avoid this, you can specify a (server-specific) TransactionManagerLookup in the Hibernate configuration: Hibernate will then register the Session with JTA transaction synchronization on close, providing proper cache callbacks after JTA transaction completion.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 06, 2004 3:02 pm 
Regular
Regular

Joined: Thu Jul 01, 2004 12:13 am
Posts: 68
Location: San Diego, CA
Did you come up with a solution to this? I am working on the same issue, so maybe we can help each other. I reconfigured my applicationContext.xml as below, but I am still unsure how to implement now. I'll post back as I find out some things.

Lou

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
   "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
   <bean id="clmDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
     <property name="jndiName"><value>clmDataSource</value></property>
   </bean>

   <bean id="mySessionFactory"
      class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
      <property name="dataSource">
         <ref local="clmDataSource"/>
      </property>
      <property name="configLocation">
         <value>classpath:hibernate.cfg.xml</value>
      </property>
   </bean>

   <bean id="myTransactionManager"
      class="org.springframework.transaction.jta.JtaTransactionManager"/>


   <bean id="clmAddressDao" singleton="false"
      class="com.mitchell.services.technical.claim.dao.spring.ClmAddressHibernateDao">
      <property name="sessionFactory">
         <ref local="mySessionFactory"/>
      </property>
   </bean>
   ...More Dao's go here

   <bean id="claimDaoManager"
      class="com.mitchell.services.technical.claim.dao.ClaimDaoMgr">
      <property name="clmAddressDao">
         <ref local="clmAddressDao"/>
      </property>
      ...More Dao's go here
   </bean>

   <bean id="myClaimService"
>>>> Would this class need to proxy all my methods to all my DAOs...YIKES!!!
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
      <property name="transactionManager">
         <ref bean="myTransactionManager"/>
      </property>
      <property name="target">
         <ref bean="claimDaoManager"/>
      </property>
      <property name="transactionAttributes">
         <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
            <!--<prop key="someOtherBusinessMethod">
               PROPAGATION_MANDATORY</prop>-->
         </props>
      </property>
   </bean>
</beans>


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 09, 2004 9:51 am 
Senior
Senior

Joined: Wed Aug 27, 2003 6:04 am
Posts: 161
Location: Linz, Austria
Since Spring 1.0.1, HibernateTemplate and SessionFactoryUtils auto-detect an ongoing JTA respectively EJB CMT transaction, and automatically provide a transaction-scoped Hibernate Session for it - without Spring's JtaTransactionManager being involved (so also no TransactionProxyFactoryBean definitions necessary).

The only requirement is that you configure a corresponding Hibernate TransactionManagerLookup. Spring will then fetch the JTA TransactionManager from the Hibernate SessionFactory and use JTA synchronizations for cleaning up transaction-scoped Sessions at transaction completion.

Juergen


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 09, 2004 2:19 pm 
Regular
Regular

Joined: Thu Jul 01, 2004 12:13 am
Posts: 68
Location: San Diego, CA
jhoeller wrote:
Since Spring 1.0.1, HibernateTemplate and SessionFactoryUtils auto-detect an ongoing JTA respectively EJB CMT transaction, and automatically provide a transaction-scoped Hibernate Session for it - without Spring's JtaTransactionManager being involved (so also no TransactionProxyFactoryBean definitions necessary).


Yes, I got this working last Friday and it is extremely helpful in keeping separation of concerns between the two layers. Very nice! However, the statement above is confusing when relating back to section 7 of your article posted on this site. My understanding is that you neede JtaTransaction manager, but are you suggesting I can just use HibernateTransaction Manager? I posted my current applicationContext below. It seems to work with either one for me, but I want to use this properly.

Also, I was able to leverage the convenience methods off getHibernateTempate() without having to use the SessionUtils explicitly. I'm assuming that you use the same calls under the covers. Again, very nice!

Thanks,
Lou

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
   "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
   <bean id="clmDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
     <property name="jndiName"><value>jdbc/clmDataSource</value></property>
   </bean>

   <bean id="mySessionFactory"
      class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
      <property name="dataSource">
         <ref local="clmDataSource"/>
      </property>
      <property name="configLocation">
         <value>classpath:hibernate.cfg.xml</value>
      </property>
   </bean>

   <bean id="myTransactionManager"
      class="org.springframework.transaction.jta.JtaTransactionManager"/>

   <!-- ******** Are you saying you should use this one instead?? -->
   <!--<bean id="myTransactionManager"
      class="org.springframework.orm.hibernate.HibernateTransactionManager">
      <property name="sessionFactory">
         <ref local="mySessionFactory"/>
      </property>
   </bean>-->

   <bean id="myHibernateInterceptor"
      class="org.springframework.orm.hibernate.HibernateInterceptor">
      <property name="sessionFactory">
         <ref bean="mySessionFactory"/>
      </property>
   </bean>

   <bean id="clmClaimDaoTarget" singleton="false"
      class="com.mitchell.services.technical.claim.dao.spring.ClmClaimHibernateDao">
      <property name="sessionFactory">
         <ref local="mySessionFactory"/>
      </property>
   </bean>

   <bean id="clmClaimDao"
      class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <value>com.mitchell.services.technical.claim.dao.ClmClaimDao</value>
      </property>
      <property name="interceptorNames">
         <list>
            <value>myHibernateInterceptor</value>
            <value>clmClaimDaoTarget</value>
         </list>
      </property>
   </bean>

   <bean id="claimDaoManager"
      <property name="clmClaimDao">
         <ref local="clmClaimDao"/>
      </property>
   </bean>
</beans>


hibernate.cfg.xml:

Code:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration
    PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>
   <session-factory name="ClmSessionFactory">
      <property name="dialect">net.sf.hibernate.dialect.Oracle9Dialect</property>         
      <property name="hibernate.max_fetch_depth">3</property>   
      <property name="hibernate.jdbc.batch_size">0</property>   
      <property name="hibernate.jdbc.use_get_generated_keys">true</property>   
      <property name="hibernate.jdbc.use_streams_for_binary">true</property>   
      <property name="hibernate.show_sql">false</property>
      <property name="hibernate.use_outer_join">true</property>
      <property name="hibernate.cglib.use_reflection_optimizer">true</property>
           <property name="hibernate.query.substitutions">true 'T', false 'F', yes 'Y', no 'N'</property>
      
      <property name="hibernate.transaction.manager_lookup_class">
         net.sf.hibernate.transaction.WeblogicTransactionManagerLookup
      </property>
      <mapping
         resource="com/mitchell/services/technical/claim/dao/vo/ClmClaim.hbm.xml"
         />
   </session-factory>
</hibernate-configuration>


Top
 Profile  
 
 Post subject: Hello,
PostPosted: Fri Aug 27, 2004 1:19 am 
Regular
Regular

Joined: Tue Mar 23, 2004 2:10 am
Posts: 51
Hi jhoeller,
Please reply this post by lsacco as many people including me are confused about the best way to for using EJB CMT and spring + hibernate i say the best way...... many people do not want to use Spring's transaction here.....
but confused should they specify spring's jta transaction manager or in hibernate transaction lookup .. i too have read so many contradictory post s that i do not know what should i do right now. Please Juegen be more cllear and precise u can even post the application context file with clear entries for transaction management with EJB(SLSB) + CMT + spring&hibernate. Please do it asap.
Regards,
Shoaib Akhtar


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 27, 2004 1:37 am 
Regular
Regular

Joined: Thu Jul 01, 2004 12:13 am
Posts: 68
Location: San Diego, CA
Shabby,

It's really quite easy once you nail it. Basically, if you plan to use SLSB with CMT to access DAO POJOs built with Spring and Hibernate, then you don't have to use any transaction beans at all in the applicationContext.xml. You only need the Hibernate manager lookup class that I specify in the hibernate.cfg.xml above. That's it! Of course, you'll want to change it to whatever server platform you are running on. Here's a sample of my current xml file.

Then in your DAOs you can either use SessionFactoryUtils.getSession(SessionFactory, false) or use the hibernate methods off getHibernateTemplate(). Be sure that the second parameter is false, as that will grab the session bound to the CMT and will not create a new one.

HTH,
Lou

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
   "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
   <bean id="clmDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
     <property name="jndiName"><value>jdbc/clmDataSource</value></property>
   </bean>

   <bean id="mySessionFactory"
      class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
      <property name="dataSource">
         <ref local="clmDataSource"/>
      </property>
      <property name="configLocation">
         <value>classpath:hibernate.cfg.xml</value>
      </property>
   </bean>

   <bean id="myHibernateInterceptor"
      class="org.springframework.orm.hibernate.HibernateInterceptor">
      <property name="sessionFactory">
         <ref bean="mySessionFactory"/>
      </property>
   </bean>

   <bean id="clmClaimDaoTarget" singleton="false"
      class="com.mitchell.services.technical.claim.dao.spring.ClmClaimHibernateDao">
      <property name="sessionFactory">
         <ref local="mySessionFactory"/>
      </property>
   </bean>

   <bean id="clmClaimDao"
      class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <value>com.mitchell.services.technical.claim.dao.ClmClaimDao</value>
      </property>
      <property name="interceptorNames">
         <list>
            <value>myHibernateInterceptor</value>
            <value>clmClaimDaoTarget</value>
         </list>
      </property>
   </bean>
</beans>


Top
 Profile  
 
 Post subject: Re,
PostPosted: Sun Aug 29, 2004 11:39 pm 
Regular
Regular

Joined: Tue Mar 23, 2004 2:10 am
Posts: 51
Hello,
Thanks for your prompt answer and i understand that but one thing i am confused is the part you specified below.
Quote:
Then in your DAOs you can either use SessionFactoryUtils.getSession(SessionFactory, false) or use the hibernate methods off getHibernateTemplate(). Be sure that the second parameter is false, as that will grab the session bound to the CMT and will not create a new one.


Why should you pass false to create session as we want to attach it with EJB CMT which is correct behavior .please explain
Regards,
Shoaib Akhtar


Top
 Profile  
 
 Post subject: Re: Re,
PostPosted: Mon Aug 30, 2004 1:22 am 
Regular
Regular

Joined: Thu Jul 01, 2004 12:13 am
Posts: 68
Location: San Diego, CA
shaby775 wrote:
Why should you pass false to create session as we want to attach it with EJB CMT which is correct behavior .


Ah yes, good question, as I asked the same thing when I first played with this. Underneath the covers a HibernateInterceptor is being used (you see one in my applicationContext.xml), so what this does is open a session when the transaction is started (we use the Hibernate Lookup Manager class for BEA you see in hibernate.cfg.xml). Therefore, it is desirable to choose "false" as the parameter because this is the session you want to attach to. You do not want to create a new session (true) as this indicates that the session wasn't properly attached to the transaction and thus an error.

Give it a try...it's very neat and clean to do this way.

Best,
Lou


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.