Apr 28, 2010

How To Use Transaction Manager with @Transactional without getting 'org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here' Exception?

Its you readers who post comments on my blog often induce me to post more information and additional write ups here!I sincerely thank you for that induction you create in me! Based on the information requested, I thought of posting an article here that would help many of you (like me) who end up with the very famous "org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here".

If you are looking at the procedure to incorporate the TxManager in your spring application by making use of @Transactional annotation along with org.springframework.orm.hibernate3.HibernateTransactionManager and , here is the right information that you can make use of! This would not only help you to get out of 'org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here' exception but would also help you in understanding the rudiments involved with the transaction very easily.

Here are the basic steps that you can make use of. Let us say that you have an applicationContect.xml(This is the application context that is loaded by the contextLoaderListener/contextLoaderServlet of your application). Let us say that you have a webdispatcherservlet's webapplication context named as application-servlet.xml.

In this case, please follow the steps given below to incorporate the transactions with ease. In my opinion, it is always recommended that you have your service layer transactional . So i intend introducing the @Transactional annotations at the services in the following example!
  1. First and foremost, define the TxManager bean within the applicationContext.xml as shown below. Remember that this context is the place where you should define the component scan for the services and daos present within your application.
  2. <bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="defaultSessionFactory" />
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager" />
  3. Note that if you define the bean id of your TxManager as transactionManager, the tx:annotation driven tag can be as given below. It literally means that you need not define the name of your transaction manager in the tx:annotation-driven tag. If you have this bean's id as something else other than "transactionManager", you need to have the the additional attribute "transaction-manager" to the tx:annotation-driven tag.
  4. <tx:annotation-driven /><br />
  5. Next,define the xmlns for the tx tag as given below in the same applicationContext.xml
  6. xmlns:tx="http://www.springframework.org/schema/tx"<br />
  7. Further, you need to add the schema location for the Tx tag as shown below in the same applicationContext.xml
  8. http://www.springframework.org/schema/tx <br />http://www.springframework.org/schema/tx/spring-tx-3.0.xsd<br />
  9. Next, go to your daoImpl file say sampleDaoImpl.java and define the sessionFactory as shown below
  10. @Repository("SampleDAO")<br />public class SampleDaoImpl implements SampleDao {<br /><br />    @Autowired<br />    @Qualifier("appSessionFactory")<br />    private SessionFactory sessionFactory;<br />
  11. Remember that you have to use the sessionFactory injected in your daoimpl as shown below
  12. sessionFactory.getCurrentSession().saveOrUpdate(hibernateObject);<br />
    or
    sessionFactory.getCurrentSession().createSQLQuery("<your query here>")<br />
  13. Next, go to your service impl layer. Let us say that you have your service implementation file named as SampleServiceImpl.java. Here, you will have to introduce the @Transactional annotations. Be careful and ensure that you make the transaction read only for the find and get queries while you can make the transaction writeable in methods that updates, saves or deletes the objects in db as follows. Here, you can make the @Transactional annotation at class level as read only. When you have an update method that writes to the db, you can annotate that method with @Transactional(readOnly=false) for this would override the class level annotation incorporated as readonly!
  14. @Service("sampleServiceImpl")<br />@Transactional(readOnly = true)<br />public class SampleServiceImpl implements SampleService {<br />@Autowired<br />@Qualifier("sampleDAO")<br />private SampleDAO sampleDAO;<br />public sampleObject getObject(int id)<br />{<br />return sampleDao.getObject(id);<br />}<br />@Transactional(readOnly = false)<br />public void update(SampleObject sampleObj) <br />{<br />sampleDAO.saveOrUpdate(sampleObj);<br />}<br />}<br />
  15. That is it!!!Your application would have included the TxManager successfully! Your db calls would be then managed by the Spring defined TxManager without any problems from here!
While this depicts a very simple implementation, you can go ahead and change the properties for the @Transctional annotation further to modify the propagation and isolation levels wherever necessary! You can also implement multiple transactional managers if need be by using @Transactional("TxManager1") and @Transactional("TxManager2") and by defining the corresponding TxManagers in your appplicationContext.xml with ease!!! Hope this helps you to circumvent the famous "org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here"! Whatsoever, keep me posted and stay tuned!

If you find the information pretty helpful, I would really be happy if you would keep me posted via the comments form displayed under this article! If you had wanted some other information related to the same topic, I would suggest you to drop a note to me using the comments form for that would help me in getting back to you with the details you are in need of!

8 comments:

  1. It's awesome, you are really helpful. After reading this article, I know I am on the right track. And finally find two silly bugs of my application. My application has similar design with the one your introduce, having Entities, DAO layer, service layer and controller layer. Service layer handling the transaction service which provided by Spring annotation. Controller will only call the services in service layer.

    Here are the two bugs I found in my codes:

    1. I made a silly mistake that let application get the hibernate current session when the application startup.

    In the class "GenericDAOImpl":
    Before:

    protected Session session;
    @Autowired
    public void setSession(SessionFactory sessionFactory) {
    session = sessionFactory.getCurrentSession();
    }

    After:
    @Autowired
    private SessionFactory sessionFactory;
    public Session getSession() {
    return sessionFactory.getCurrentSession();
    }

    2. I added the tag in both application-context.xml and XXX-servlet.xml files. And obviously, Spring use DispatcherServlet one.

    ReplyDelete
  2. Hi Rico,

    Yet another pointer to you from the recent comment that you have posted. This is regarding the 2 points that you have modified.

    Regarding the first point, I understand that you have autowired the sessionFactory instead of the session as such!That should be fine

    But regarding the second pointer, I have a second thought. Actually the tag <tx: annotation -driven) should not be inserted in both the config files(appplicationContext and xxx-servlet.xml) - It should be moved to the applicationContext.xml which in turn gets loaded into the application by the contextLoaderListened. Its better that you dont introduce the txManager via the xxx-servlet.xml which is referred to as the webapplicationcontext of your application xxx.

    Let me know if you need more explanation on this!

    ReplyDelete
  3. Thanks, you saved me a lot of time...

    ReplyDelete
  4. Hey akash, Thanks for letting me know about it!

    ReplyDelete
  5. Great post! I missed
    xmlns:tx="http://www.springframework.org/schema/tx"
    in my config file. Thanks for help!

    ReplyDelete
  6. Thanks a lot man... It will be really great if u could explain the attributes of the Transactional annotation with examples.. mail me when u r free... softwarevasanth@gmail.com

    ReplyDelete
  7. Great post..

    It helped me fix my problem but..

    I had error NoSuchBeanDefinationException for hibernateTransactionManager





    and in


    Then I changed the id to "transactionManager" and remove transaction-manager property from tx:annotation element.

    It started working.

    Then I changed it back to what it was and it is still working.

    Thanks any way

    ReplyDelete