Java

Easy Hibernate Transactions

Trying to manage transactions can get ugly. Sure, you can gloss over the issue, treating each insert/update/delete as an atomic transaction – if you like your database in an inconsistent state, or have a trivial database. At some point, though, you’re likely to decide you need transactions, or else your logic attempting to keep the DB consistent will become unmanageable. At first, it seemed cumbersome – needing to pass the Hibernate session around to every persistence method that I wanted to share in the transaction. Then, I discovered a better way.

In using Hibernate for persistence, I often happened upon the discussion of a ThreadLocal, but frankly found the term a bit unintuitive and intimidating. Let me distill it so you don’t have to wade through things – for Hibernate’s needs, ThreadLocal allows you to create a singleton per thread. In most web applications, a single request follows a single thread of execution until it returns a response to the user. By using this ThreadLocal type of object, we can access the same session throughout the web request without having to pass it around.

Here are the general pieces of a suggested approach:

  • Servlet Filter – The servlet filter exists to intercept requests and open and close the session and store it in the ThreadLocal. It also contains a getSession() method, used to get or create a session for this thread. Sample code for Persistence class here.
  • Data Service Classes – the classes you call to get your data. These classes request their session using Persistence.getSession().
  • Business Logic Classes – these classes encapsulate the business logic, including the logic surrounding multiple database interactions.

So a method of your Data Service Class might look like this:

public static void update(User u) {
   Session sess = Persistence.getSession();
   sess.update(u);
}

A method in your business logic could look like this:

public void updateBoth( User user1, User user2 ) {
   Transaction tx = Persistence.getSession().beginTransaction();
   try {
      UserService.update(user1);
      UserService.update(user2);
      tx.commit();
   } catch (Exception e) {
      Persistence.rollback(tx);
   }
}

Instead of writing cumbersome open/close session logic in our persistence classes, or having to pass the Session into each method, the approach lets us cleanly share a session across multiple persistence calls in a simple, thread-safe manner. This discovery has made my persistence code much cleaner, and I hope that you find it beneficial as well!

Advertisements

7 thoughts on “Easy Hibernate Transactions

  1. You might want to take a look at Spring. It wraps up Hibernate transaction management beautifully, allowing you to use declarative transaction management (using JTA or not, it’s an option).

  2. To the anonymous user – not sure what you mean by “get an app server” – this is within an app server. The app server won’t manage all this cruft for me unless I am using Entity Beans (no).

    Regarding Spring – that’s on my list of things to look into. I’ve looked at quick intros to it, but I never have enough time to actually sift through the xml and bean declarations to actually understand it.

  3. Besides transaction safety your solution has another advantage: lazy-loading! Typical DAO method implementations look like this: get a connection, do some sql, close connection. Hibernate can load collections on demand by using proxies. But if you close the connection inside your DAO lazy loading will not work outside the DAO. Therefore it is a good idea to open the session in a filter and close it at the end of the request processing. Spring has a ready to use filter for this: OpenSessionInViewFilter.

  4. I agree: spring is the way to go: Hibernate feels “too low level” a component, when one has learnt how to use it inside Spring: it’s just too easy: check out the article juergen hoeller posted on the hibernate wiki, it’s pretty clear and complete.

  5. Concerning the OpenSessionInFilter pattern, does it only work if the web and EJB containers are colocated ? I think that’s a real pre-requisite if one has SLSBs (Stateless session beans) fronting DAOs (your Data Service objects). Care to comment ?

    fermat

  6. Concerning the OpenSessionInFilter pattern, does it only work if the web and EJB containers are colocated ? I think that’s a real pre-requisite if one has SLSBs (Stateless session beans) fronting DAOs (your Data Service objects). Care to comment ? fermat

    A fine question. To be honest, I’m not certain, but I’d imagine that it wouldn’t work in that circumstance. Since the session is in the ThreadLocal, and the Thread itself won’t propagate to the remote container, I doubt the session will either, unless you explicitly pass it in your remote method call.

    Typically, a physically removed business tier as you describe is fronted by a Session Facade. In this case, I’d imagine that each invocation to the remote interface would represent a unit of work, and that it would be appropriate to wrap each remote method in a session.create() and session.close(). To automate this, as we have done for web requests, you might use an AOP interceptor.

Comments are closed.