Hibernate Sessions in Two Tier Rich Client Applications

One of the most populare articles in this blog so far ist the one about, well: Hibernate Sessions in Two Tier Rich Client Applications. Although the original article is writen in german I keep refering to this article, even in english communities. Therefore I decided to break my habit of writing articles in german only and provide a english version which you are reading right now.

This is NOT a direct translation so there might be some differnces in scope, focus and detail.

Everybody working with Java and Databases is probably aware of Hibernate. It is a great solution for mapping a database schema to a object model. It is used in hundreds of applications. So on my current project we decided to use it as well. But big surprise. While Support in the user forum of hibernate is pretty good most of the time we hit one kind of a problem which had no apropriate solution available: How to handle Sessions in a Two Tier Hibernate Application (Swing or SWT typically).

How could such a essential problem be unsolved? Well Rich Client Applications are not hip anymore. Everybody goes for web applications and in that context the session handling is well understood and there is a easy straight forward solution that works in most cases: On each request open a session, do all your work including constructing the result (e.g. JSP) , close the session. But there is no equivalent for a request in a swing application. And since Rich Client Applications are kind of old fashioned nobody bothers to find (and write about) a clean solution for this problem.

We tried a lot of things, starting with the antipattern of a single session per application. This doesn’t work at all for any kind of serious app for the following reasons:

  • No transaction control between different parts of the application. When you flush/commit a session, everything gets flushed. So imagine a application with two open edit frames. The user hits save in one frame and surprise, her half done changes in the other frame get saved as well. Not good.
  • Memory Leak. The Hibernate Session keeps track of every entity ever loaded by that session. So if you don’t close the session from time to time the session will grow until the application blows up or the whole database is contained in the session. If nothing else this will cause performance issues.

Of course if you write a really small simple application this might work, but not for us. As said before we tried a lot of things to solve our problem in the assumption that our requirements are so common that it can’t be hard to find the solution. We were wron. So if the solution to a problem isn’t easy to find, what should be your first step? Wrong (probably)! Your first step should be to exactly identify the problem. In this case this meant: What are the requirements we had? What are the relevant features/limitations of Hibernate? The requirements were:

  • We want Lazy Loading: Lazy Loading is a real powerfull feature whe working with a rich domain model (as we did) especially in a Swing Application. You just display what every attribute you can reach by any kind of object navigation, hibernate will ensure the data is there. Awesome. This was one of the main selling points for Hibernate vs. plain JDBC. So it wasn’t realy an option to loose it.
  • Different views of the same entity should show the same state. So if you edit an Object the same Object shown in some kind of list-view should show the updated state immediatly.
  • It should be obvious for the user what is going to be saved when she hits the save button.
  • The whole mechanism must be fairly easy to use, since the team was growing and not everybody was a hibernate expert. Also lazy loading problems are sometimes hard to debug and fix.

The relevant properties of the Hibernate session are

  • For lazy loading to work an entity must be attached to a open session.
  • A entity wich contains at least one collection (which are well above 50% of our class) can only be attached to one session at a time.
  • A session keeps a reference to any entity it loads, until the entity get evicted or the session gets closed.
  • A Hibernate session guarantees to return the same instance everytime a specific entity is requested.

If you look at it in this compact form it is rather obvious that you can’t have your cake and eat it too. The automatic refresh in all views of an object would be easily implemented, when there is only one session. But we simply couldn’t do this. So the decision was made that the automatic refresh is (obviously) not as important as clean transactional control plus lazy loading. So we will have more then one session. But which part of the application is using which session? The Hibernate site uses the term ‘Unit-of-Work’. Each unit of work should be contained in its own session. But this is basically back to step one. A request in a webapp ist a unit of work, but where is a unit of work in a rich client app? Imagine this example: The user fires up the application and opens a search dialog resulting in a list of objects. Clearly we are accessing the database, so we just startet a unit of work. Now she double clicks an item in the list. The entity gets opened in a editor, she edits it and hits save. Work commited, transaction closed, unit of work ended. Wow, thats easy, isn’t it? No it isn’t: She clicks on a different item, edits it, saves it. So now we have opened one session and closed two sessions. Not good.

The answer is actually fairly easy once found: Use one session per frame/internal frame/dialog. Modal dialogs use the session of the frame the got starteted from. Background tasks get their own session. The critical point is the transfer of objects from one frame to another. It is tempting to just pass the object but then you have a object from the wrong session in the frame. Instead pass just the Id (the primary key) and use that to load the object in the new session. This approach solved most of our problems nicely.

Most problems? Yes and no. We have some things that we don’t like to much. I think I know how to solve them but I haven’t implemented them yet. So I can’t really promis anything.

  • Instant refresh in other (readonly) views. When editing a object the changed state is not represented in other views of the same object. This could be fixed by a hibernate interceptor or event listener. It would listen for update events, then check if this entity is contained in any other session, check if that session is read only and if so trigger a refresh of that object. We haven’t implemented that simple due to time constraints.
  • Saving in background. Most of the stuff we do is simple object editing, but on fairly complex object graphs. So saving an object to DB may take some time. Due to the tight integration of Frames and session we can’t easily delegate this work to a background thread. The same is true of lazy loading. In long lists of complex objects scrolling to new cells for the first time might cause some lag, because lazy loading happens in the Event Handling Thread. The first part should be fairly easy to fix:Open a new Session, find the dirty Objects, merge the dirty Objects in the new Session, do a flush of the new session in a background thread. One just has to make sure the background thread uses its own instances, not the same instances as the original frame/session. The lazy loading in background is more difficult to solve. For almost everything in the GUI we use a JGoodies PresentationModel and the associated ValueModels, so the swing objects don’t access directly any attributes of our Hibernate entities. These ValueModel could be used to implement a seperation of two differnt threads: The Swing Event Handling Thread on one side and a seperate thread for all the model work, including lazy loading. But this would mean the whole application is split in two threads, instead of the normal aproach of having one main thread and a couple of worker threads for special work. I think it should be feasibly and actually enforces a very strict and clean architecture, and result in a highly responsive gui, but it would also be a lot of (debugging) work and as everybody knows: Concurrency is hard. So we decided that we don’t need it in this application.

If you are going to implement this kind of session handling I strongly suggest to use a director/mediator pattern for all your frames. While always a good idea, it becomes important in this case because it gives you a well defined spot to do your session handling. And of course you should be aware of the alternatives:

  • Go with a single long living session. Only feasable with smallish applications
  • Kick Lazy Loading and close your session after retrieving your objects. This loses many of the interesting benefits hibernate offers.

In any case I how this write up shed some light on the issues and helped to make a informed decission.

This entry was written by Jens Schauder , posted on Sunday September 28 2008at 11:09 am , filed under Java, Softwareentwicklung . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

13 Responses to “Hibernate Sessions in Two Tier Rich Client Applications”

  • Fabio says:

    Very good article.
    NHibernate (the .NET version of Hb) users have the same problem with WindowsApplication.
    I’m trying to implement a solution using session-per-application-transaction pattern for application that are using MVP pattern… but as you know… this is a long story.

  • Vishal says:

    Nice Article !!!
    I am facing the same issue.

  • Ewan Makepeace says:

    We too are facing the same problems on the .NET side. The Hibernate team are just a bit too smug about how awful the world would be if Hibernate just opened a new session every time it needed to lazy load a collection, but in fact the problems they have created are much bigger than the ones they describe, when you are talking about rich client apps.
    The whole point of using Hibernate is to encapsulate persistence to make your code clean. The problems described above mean that session handling and persistence concerns must be embedded all over your code (and often in the UI where you want it least!).

    If anyone has further references on this subject would love to hear about them. I cant believe there is so little good info on this subject…

  • Richard says:

    We are trying to write a rich application using ZK framework http://www.zkoss.org/ where the rich client applications run as a session variable on web server. So in our case we also have to consider sessions maintained across multiple http request/responses – add yet another layer of complexity…..

  • aappddeevv says:

    You can have a session stay open within a RCP based on the lifetime of the unit of work which is typically an editor screen of some sort while still having different session patterns on other editors windows in the same thread by using orchestra and spring. By placing DAOs or services into a special scope that intercepts all methods on those DAOs and swaps out the session on the thread and then replaces it after the method complete automatically using orchestra. Orchestra is from a myfaces implementation. This makes conversational control placed into the scope versus using program code. This is essentially what jboss’s seam does.

    In the worse case you can just create your DAO objects with the long-lived session object directly and maintain the session object in your editor state somewhere. Then just ensure that all other DAOs that are called use that same session by initializing them with it as well. This approach is harder but also doable.

    The only other way is to do the second approach via code instead of a container which makes configuration more laborious but is what many RCPs have done over the years.

    Supposedly the new JSR 299 (or something like that) will address conversational scope and should apply to RCPs.

  • Hi Aappddeevv,
    well I just added Orchestra (http://myfaces.apache.org/orchestra/) to the many thing I’d like to investigate. It sounds interesting in deed. Yet so far I fail to see how one could specify the scope of a conversation in an easy way. Do you have more detailed sources for that?

  • sola says:

    Great article!

    Of course rich client applications have a lot of other problems like this:
    - Database connection needs to get through firewalls
    - The database connection can be easily broken over the Internet (we use PostgreSQL and have to implement reconnection functionality because the connection so often get lost on long distance sessions)

    I really like rich clients but the ORM frameworks most often simply don’t consider the extra needs of these kinds of apps which makes them hard to develop.

    We also opted for the one Session for one Frame approach (or something very similar).

  • Milan says:

    Excellent article!

    Here is my concern: how to handle database errors/constraint violations. The scenario is as follows. User changes several records in a grid or in different parts of one form (frame). When user saves the changes, hibernate flushes all changes to the database. Some of the changes are successful and some of them fail DB constraints. Ideally, you would want to navigate to the UI element that caused the constraint failure, and give the user a chance to fix the error, while preserving the valid changes.

    Here is an excerpt from Hibernate documentation: “If the Session throws an exception (including any SQLException), you should immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state. No exception thrown by Hibernate can be treated as recoverable. Ensure that the Session will be closed by calling close() in a finally block.”

    If there are multiple failures, it gets even more complicated.

    Your thoughts on the error handling subject would be much appreciated.

  • Hi Milan,
    you are absolutely right, this is a problem that needs consideration.

    I absolutely recommend to validate all input against the constraints before flushing the session. In the project on which this article is based we basically used a NakedObject appraoch (http://en.wikipedia.org/wiki/Naked_objects) although we didn’t know it at that time. So we actually used the constraints as defined in the hibernate mapping to create checks/special UI control in the UI layer. So for Foreign Keys one only could choose by picking from a list, other values where checked using hibernate validation.

    If everything fails and you actually get a sql exception due to a constraint violation the session is dead, which sucks, but is seldom.

    An alternative approach is to edit data in special objects and then copy the content of those objects into the session objects. This results in much shorter session live time (which probably is a good thing), and of course you could recover more easily after an exception. But you need to create a seperate set of objects (possibly classes), which makes life even more complecated then it is already. …

    As a German saying goes: You have to die one death

  • Milan says:

    Hi Jens,

    Regarding the constraints validation in the client, that is definitely the best approach when possible. However there are certain constraints that are more convenient to validate in DB or they perform better there, such as Unique Key, or complex business rules implemented in DB triggers.

    I did some experimenting with the error handling and found out the session does not die after a SQL constraint exception (at least I could not make it die). If you handle exception and subsequently fix the data that caused the constraint to fail, everything works properly at the end. You can have multiple DML operations and fail only some of them, commit or rollback at the end (intentionally), etc.

    So here is my idea about how to apply this to user interface. Trap every focus/selection change event that causes the underlying data context to change, and flush the session each time. Catch the error, display it (in a dialog) and do not allow changing the selection until the error is corrected (or the changes are rolled back). I successfully implemented a simple prototype that follows this approach. The biggest hurdle for me is to find proper events where to flush the session. (I am using SWT and it is not working as I would expect it.)

  • Hi Milan,
    I’d be super carefull with this approach. I would love if it works, but it will always be without support of the hibernate team, so if it failes at some point you will be on your own completely. One case which I would expect problems with is: how does it handle the dirty state of objects that already got flushed successfully? Is it set to ‘not dirty’ as it probably should? What if the sql exception happens on an update that happens in mutiple steps, which might be the case when manipulating references.

    If you want to go down this road I’d check the source code, write some tests and then propose a patch for the hibernate team to make it an official feature. This way you know (to some extend) it works, and it will get some support from the hibernate team and the community as well.

  • Vlad Sadilovskiy says:

    Hi.

    I wanted to say that validating some type of constraints is not possible even conceptually in the application layer without locking tables that are involved in such validation. Consider unique key validation. The only way that guaranties uniqueness and would not throw a unique constraint violation is to do the following sequence of actions. 1. Lock the table from modifications 2. Query this table for duplicates of an incoming data. 3. If no duplicates found, insert incoming data. 4. Unlock the table or commit transaction. This is workable, but in my opinion cannot be a solution for concurrent multi-user enterprise level application.

    Any other algorithm may render the assumptions of querying for duplicates invalid at the time of the insert.

  • Hi Vlad,
    Your assessment of validation unique constraints is absolutely correct. And for this reason I strongly recommend the use of database constraints, which do essentially what you describe with pretty good performance and very well tested.

    Yet ‘enforcing’ this kind of constraint in the gui, without using the locking catches many cases of constraint violation, which would otherwise only get caught by the database, rendering the session unusable.

    There is only a small gap left, for another user entering the same value at almost the same time and the database constraint takes care of that.

    The performance cost of this approach is very limited, since we only use a select on an indexed column and no locking.

    So for us it was a nice compromise between performance, ease of implementation and usability.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>