Steve just committed a new interface and extension point to Hibernate Core. We can finally plug-in custom Session context management into Hibernate. For those of you who already know getCurrentSession() in Hibernate 3.0, this new extension enables the same without a JTA environment.
But how does it work? In a J2EE container we can rely on the scope of the current JTA transaction to bind the Hibernate Session. So whenever you call getCurrentSession() you get exactly that. Outside of a container, however, we don't really know when a Session ends (starting it is easy: the first time you request one).
So, a new interface was needed to allow Hibernate users to provide a
Session. In fact, the interface CurrentSessionContext has exactly this
single method you can implement. But you don't have to, there are two default
implementations distributed with Hibernate 3.1:
- The usual behavior for JTA environments, binding the current Session to the current system transaction This works without any extra configuration, just set up Hibernate for managed J2EE use (transaction manager, etc.), and call sessionFactory.getCurrentSession(). No need to flush or close the Session. If you use CMT, transaction demarcation is declarative, if you use BMT, call the methods beginTransaction(), getTransaction().commit(), and getTransaction().rollback() on the current Session. If you want to you can enable JTA context management in your Hibernate configuration by setting the new property current_session_context_class to "jta", but again, it is the default if Hibernate is configured for J2EE.
- An implementation for typical Hibernate deployment in non-managed environments, binding the current Session to the current thread. However, this implementation needs a little help from you to mark the end of a unit of work (we can't wait for the thread to end). You have to call the static method ThreadLocalSessionContext.unbind().close() to remove the current Session from the thread, and to close it. To enable this context handler, set the current_session_context_class configuration property to "thread".
Of course you can implement your own CurrentSessionContext and name the class in configuration, for example, to implement a Long Session (or in new terms: extended persistence context) pattern with EJBs, storing the disconnected Session in a SFSB between requests and JTA transactions.
The traditional HibernateUtil class can now finally be reduced to a simple startup helper, used to initialize a SessionFactory. This is how a typical data access routine now looks like in CMT, BMT, and non-JTA environments:
Session s = HibernateUtil.getSessionFactory().getCurrentSession(); s.beginTransaction(); s.save(item); // or HibernateUtil.getSessionFactory().getCurrentSession().save(item); s.getTransaction().commit(); ThreadLocalSessionContext.unbind().close(); // Only needed for non-JTA
With HibernateUtil we don't really care where the SessionFactory is coming from, either static singleton or from JNDI. The last line is only needed for the built-in
thread context handling outside of an application server, as explained above. The rest of the code is the same everywhere, in all deployment situations. Usually you would unbind and close the Session in some kind of interceptor and encapsulate the last line in some system class that knows when request processing completes. The two lines of code saving an item are equivalent, the purpose here is to show you that you can call getCurrentSession() as many times and in as many different (DAO) classes as you like.
For all of you who don't want to build Hibernate from CVS to try this new feature: I've prepared an updated CaveatEmptor release that includes a snapshot of Hibernate 3.1 from CVS, updated HibernateUtil, and updated DAO/unit test classes. The other Hibernate documentation (and the popular Wiki pages about Session handling) will be updated later, when an actual 3.1 release is available.