A smoother, gentler hibernation

Last week, while optimizing a Java app, we have stumbled upon an interesting trick.

Well, I suppose it’s interesting since I haven’t been able to find out any trace of it in Hibernate docs or FAQ.

So, you are using Hibernate for O/R persistence layer of your latest Java app. Welcome to the club.

Suppose that your app is distributed or your business logic is on multiple servers for performance reasons. In other words, your database is very frequently accessed from multiple points. Thus, each and every display of a projection of your data (like, an innocent “patients list” screen) has to perform a data retrieval operation, aka SELECT. You are not yet at the point of giving up realtime functionality for performance reasons (via complex caching), but however your queries seem pretty slow. And still, you are using probably the faster O/R mapping tool alive.

Easiest path to data persistence passes through Hibernate Transaction API. And your transaction looks like that (c/p from the docs) :

[...]Session s = sessions.openSession();Transaction tx = null;try{    tx = sessions.beginTransaction();    fooList = s.find(    "select yummy from Big where complex");    tx.commit();}catch (Exception e){    if (tx!=null) tx.rollback();    s.close();    throw e;}return fooList; //or something similar, which goes to the view, via controller[...]

And here’s the trick, if you do only SELECTs, there is no point in commiting the transaction. Because (and I’ll quote again the manual):

“Flushing the session

If you happen to be using the Transaction API, you don’t need to worry about this step. It will be performed implicitly when the transaction is committed.”

Even if you know for sure that you haven’t modified your data, the API still has to check for modifications ! And when data is pretty complex, this might take a pretty long time. Therefore, the following approach :

[...]Session s = sessions.openSession();Transaction tx = null;try{    tx = sessions.beginTransaction();    fooList = s.find(    "select yummy from Big where complex");    tx.rollback();}catch (Exception e){    if (tx!=null) tx.rollback();    s.close();    throw e;}return fooList; //or something similar, which goes to the view, via controller[...]

shoudn’t change anything in application behavior, all for a “transaction time” divided by 3.

Hey, that is great… The app runs sensibly faster – for one line of code.

Feedback: We do have now a “documentation-compliant” solution thanks to Viktor Szathmary, who suggested a session.setFlushMode(FlushMode.NEVER) for the specific session. We haven’t yet profiled this, but. However, we have a problem due to the fact that each session is used a few times before being thrown out. No, we do not pool Hibernate sessions but there’s a fair bit of reuse sometimes, behind the business logic. Depending on the type of transaction implied, the setFlushMode should change (or not). Ok I have to admit it’s a legit idea, but it’s a supplementary line of code. And where’s the fun ? :)

Comments

Tags