With such a controversial title, I’m bound to be the target of heated comments. Although provocative, such is not my goal, however, I just want to initiate an educated debate between people that are interested into thinking about the problem.
The origin of this post was a simple discussion between developers of different level of experience on Hibernate. The talk was about eager-, lazy-loading and the infamous LazyInitializationException. Since I imagine not everyone has the problem in his mind right now, let me resume it at first.
Most of the times, your entities have relations to one another: a course has students, an invoice has a customer, etc. These relations could take you really far (a student follow courses, which are taught by teachers, who in turn have other courses), and since most of the time, you don’t need the whole objects cluster, Hibernate let you define relations as either eager or lazy. Eager relations do get the association, while lazy relations are replaced by Hibernate by a proxy. These proxies do nothing until activated by calling the getter for the association. At this time, the proxy queries the database through its encapsulated Hibernate session.
If the latter is already closed, you’ll get the LayInitializationException, since Hibernate tries to query the DB without connection. However, there are 3 solutions to the exception.
The simplest is, of course to tag the relation as eager. Hibernate will never use a proxy, and thus, you’ll never have this exception (from this relation at least). This is not a solution per se, since if you do this with all relations, Hibernate will load all associations, and you’ll end up with a mighty big objects cluster. This defeats Hibernate lazy strategy as well as clutter the JVM’s memory with unused objects. Associations that are used throughout the application are a good candidate for eager tagging, but it’s the exception, not the norm.
Another solution for this is the OpenSessionInView "pattern". Before going into explaining it, let me layout the whole thing.Good web applications are layered, meaning the persistence layer (the one nearer to the database) is responsible for interacting with the DB. Most DAO will open the Hibernate session at the beginning of the method (or get it from the current thread but it’s another matter), use it to CRUD the entity. and return control to the service layer. From this point on, there should be no more interaction with the DB.
Now the "pattern" tells us that if an Hibernate proxy need to access the DB in the presentation layer, well, no problem, we should open the session on demand. This approach has 3 big disadvantages IMHO:
- each lazy initialization will get you a query meaning each entity will need N + 1 queries, where N is the number of lazy associations. If your screen presents tabular data, reading Hibernate’s log is a big hint that you do not do as you should
- this completely defeats layered architecture, since you sully your nails with DB in the presentation layer. This is a conceptual con, so I could live with it but there is a corollary
- last but not least, if an exception occurs while fetching the session, it will occur during the writing of the page: you cannot present a clean error page to the user and the only thing you can do is write an error message in the body
Another variant of this is to use Value Objects and let a mapping framework (such as Dozer) call your proxied getter methods in the service layer. This let you correctly handle errors but your number of queries is still the same.
The best solution I’ve found so far to lazy initialization is the "join fetch" feature in Hibernate, available from both the Criteria API (setFetchMode(association, FetchMode.EAGER)
) and HQL (JOIN FETCH
).
This means your query methods will be aimed at providing a full objects cluster to your upper layers.
This also means, and I must confess this is a disadvantage, that your presentation/service layers will leak to your persistence methods:
for example, you will have a getCourseWithTeacher()
method and a getCourseWithStudents()
method where in both cases some relations will be eagerly fetched (the teacher in the first case, the students in another).
Nevertheless, this approach let you do only one query for each screen/service and it lets you cleanly manage your exceptions.
I see only a use case for OpenSessionInView: if you have a bunch of junior Hibernate developers, no time to properly explain them the whole shebang, and no performance issues (perhaps because of a very simple entity model or from very simple screens), then it is a good trade-off (but still not a pattern). As soon as you diverge from this configuration, it will lead you to a world of pain…
I’m interested in having your inputs and arguments about advantages I may have missed about OpenSessionInView so long as it has nothing to do with:
- I’ve always done so successfully
- I never had any problems
- XXX advertise for OpenSessionInView in YYY book (yes, I know about Gavin King but it shouldn’t stop anyone from thinking on his own). A variant of this is: the ZZZ framework has a class that does it (I know about Spring too)
I’m also interested in other solutions for the LazyInitializationException
, if you’ve have creative insights about it.