Announcement Announcement Module
Collapse
No announcement yet.
When to use HibernateTemplate.execute and HibernateCallback Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • When to use HibernateTemplate.execute and HibernateCallback

    Seriously. Can't find a straight answer anywhere.

    Why would I want to use HibernateCallback instead of just doing something easy like:
    Code:
    Query query = getSession().createQuery(hql).list()
    It HibernateCallback a legacy thing? Wouldn't Spring handle cleanup/closing the session in the above example?

    Thanks-

  • #2
    This is my impression as well. I don't actually know the history, but from reading some of the reference guide comments, it seems like hibernate used to be more difficult to use in the past.

    It looks like HibernateTemplate was created as sort of the 'cant get it wrong' class for people with simple requirements.

    I'm guessing that HibernateDaoSupport came first, was hard to get right, then they created HibernateTemplate to make cleanup easier, then things evolved to the point where you can use the SessionFactory directly and spring's aop stuff will cleanup after you; so now the 'recommended' approach is the one you describe.

    Comment


    • #3
      You are both wrong... Hibernate 2 was a nightmare to use, checked exceptions every where, that is where HibernateTemplate/HibernateDaoSupport came from. Since hibernate 3.0.1 the hibernate guys finally got it right and managed to get integration for 3 party frameworks right (contextual sessions) since then it isn't recommended any more to use HibenateTemplate/HibernateDaoSupport.

      They are still there for backwards compatibility and easy migration from hibernate 2 to hibernate 3 (you only need to change the package!).

      Code:
      Query query = getSession().createQuery(hql).list()
      Regarding your initial sample, no spring wouldn't mange this session as getSession in general creates a NEW session outside the scope of spring (the same as calling openSession instead of getCurrentSession) hence you would end up with an open session until it times out. In general when you use getSession you should also call releaseSession.

      Comment


      • #4
        Wow, getCurrentSession() vs. getSession() thats never going to be confusing. Why not name it getManagedSession() and getUnmanagedSession() or getCurrentSesion()/createSession().
        When I read it, i read it as getCurrentSession() and thought, thats fine, its just like the example.
        Last edited by honeybunny; Apr 30th, 2010, 10:34 AM.

        Comment


        • #5
          getSession is on HibernateDaoSupport, getCurrentSession is on the sessionfactory.

          I.e
          getSession is Spring API

          getCurrentSession/openSession is plain hibernate API.

          In general if you use HibernateDaoSupport don't use getSession but use a HibernateCallback. If you really must.want to use getSession you must understand what is happening underneath. Rule of thumb if you are using HibernateDaoSupport and getSession also release the session. However I wouldn't suggest using HDS/HT anymore but simply use the plain Hibernate sessionfactory.
          Last edited by Marten Deinum; Apr 30th, 2010, 11:33 AM.

          Comment


          • #6
            How do you bind the session to the thread when not using HibernateTemplate?

            Comment


            • #7
              You don't.... Spring takes care of that.

              Comment


              • #8
                Then I'm doing something wrong. If I remove the hibernate callback code around my query, I'm getting something like that:

                (code is calling @MethodAttribute annotated method)

                Code:
                10:00:40,175 DEBUG HandlerMethodInvoker:146 - Invoking model attribute method: public com.test.dbo.Person com.test.controller.PersonController.populateModel(java.lang.Integer,javax.portlet.PortletSession,org.springframework.web.bind.support.SessionStatus)
                10:00:40,176  INFO PersonController:207 - lookup project with id 2
                10:00:40,176 DEBUG PersonDAO:113 - getting Person instance with id: 2
                10:00:40,177 DEBUG SessionFactoryUtils:316 - Opening Hibernate Session
                10:00:40,178 DEBUG SessionFactoryUtils:789 - Closing Hibernate Session
                10:00:40,181 ERROR PersonDAO:130 - get failed
                org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

                Comment


                • #9
                  1) Add a HibernateTransactionManager
                  2) Configure transactions
                  3) Use sessionFactory.getCurrentSession not openSession or getSession

                  The above applies if you use a plain hibernate API dao. If you use HibernateDaoSupport you should use HibernateTemplate...
                  Last edited by Marten Deinum; May 3rd, 2010, 04:11 AM.

                  Comment


                  • #10
                    1) Add a HibernateTransactionManager
                    check,

                    Code:
                    <bean id="transactionManager"
                    	class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                    	<property name="dataSource" ref="dataSource" />
                    	<property name="sessionFactory" ref="sessionFactory" />
                    >
                    </bean>
                    Code:
                    2) Configure transactions
                    Check? Not sure. I'm using @Transactional at service layer, I've read here in the forums, that this is fine (and better than on DAO layer, which seems logical to me).

                    Code:
                    <tx:annotation-driven transaction-manager="transactionManager" />
                    3) Use sessionFactory.getCurrentSession not openSession or getSession
                    Check.


                    Edit: It's pretty plain, no extending of any Spring/Hibernate classes.
                    Last edited by TRex2003; May 3rd, 2010, 04:17 AM.

                    Comment


                    • #11
                      Your service layer is transactional but judging from the stacktrace you are bypassing the service layer and accessing the dao directly from the controller...

                      4) Make sure that you have 1 instance of the service, component-scan scans the classpath if it is in the ContextLoaderListener and DispatcherServlet you might have 2 instances of the same class. 1 with transactions the other without. (Search the forum as how to solve that has been answered numerous times).

                      Comment


                      • #12
                        It's working, at least where it should for sure. In fact, I have no idea why it's working *now* and not before. My last changes were to comment/uncomment a transactionInterceptor which should be obsolete in my configuration, but that wasn't causing the error with the sessionFactory in general. I'll post it, if I find it.

                        This will keep me awake

                        The stacktrace shows this code snippet running (failing):

                        Code:
                        	@Transactional(readOnly = true)
                        	@ModelAttribute("Person")
                        	public Person populateModel(@RequestParam(value = "pId", required = false) Integer id,
                        			PortletSession session, SessionStatus status)
                        		{
                        
                        		log.info("lookup project with id " + id);
                        		if (id != null)
                        			{
                        			PersonPPC pPersonbo = getBo(this.PersonDAO.findById(id));
                        			System.out.println("#+++++++# Size = " + pPersonbo.getPersonnamens().size());
                        			return pPersonbo;
                        			}
                        		else
                        			return getBo(new Person());
                        		}
                        where getBo(Person) creates a businessobject which acts as some kind of proxy (some sorting, some more properties for accessing collections, mostly passing through). The service layer has no general logging currently, need to add that.

                        It still fails at the collection, because the session is instantly closed after fetching the object. OSIV should intervent, but it doesn't, when posting. An hour ago, it failed everytime (even with OSIV working, =at listing). I'd rather open a new thread for that; the sessionFactory thing is done (and I still feel stupid because of not knowing why).

                        Comment


                        • #13
                          I don't see a service layer, you are calling the DAO directly and not through a service layer. Next to that post your dao to check if something is going on there.

                          I also suggest to not make your Controllers transactional it is the service layer not the web layer that should be transactional.

                          You are now bringing in the OSIV make sure it is the FIRST filter applied and that it applies to /* or at least your DispatcherServlet.

                          And as I stated make sure that you have 1 instance of everything, that is hard to judge without the configuration.

                          Comment

                          Working...
                          X