Escolar Documentos
Profissional Documentos
Cultura Documentos
One of the potential problems with object/relational mapping is that a lot of work has to be done to
convert relational results into object results. Because of the nature of an object-level querying and
criteria system, the results returned by a query in an O/R mapping tool will potentially be much
more coarse than what you might be able to achieve via standard JDBC calls. Tree structures are a
fully populated Node object, it potentially would have to load the entire 'Node' table. For instance,
-A
|
*---B
| |
| *---C
| |
| *---D
| |
| *---E
| |
| *---F
| |
| *---G
*---H
If you were to ask a naive O/R mapper to load C, it would have to load B (due to the parent
reference). To load B, the O/R mapper then has to load D (due to the children reference). D then
has to load E, F, and G. Then, to continue loading B, the O/R mapper has to load A, which then
loads H. It's possible that all we wanted was the name of C, however, and simply by loading C, we
have loaded the entire tree. In the mean time, each association population would require a unique
SQL select. By my count, that is around 8 gazillion SQL statements for just the example above, and
the number of SQL statements grows *linearly* with the number of nodes in the data. The
Hibernate is not a naive O/R mapper however. Instead, Hibernate does an excellent job of
providing many APIs to minimize the impact of a query, and to make sure that you're not doing too
much work for the result you want. For one thing, Hibernate supports scalar queries, so you could
simply get the name, and be done with it (that's a discussion for another day however). In
addition, if you really did need the whole tree, Hibernate supports join-style fetching so that the
linear select situation can be minimized down to a couple (or even 1!) select statements (that is
Hibernate is so Lazy!
Hibernate also supports the concept of 'lazy' fetching. Lazy interaction is discussed in more detail in
Chapter 20 of the Hibernate 3.0 Reference Documentation. When working with Hibernate, it is
*critical* to understand lazy associations, as they can be your best friend, but if you don't treat
them right, they can be your worst enemy. Besides, most lazy fetching strategies have been
Hibernate provides three forms of lazy fetching - lazy (single-point) associations, lazy collections,
and lazy properties. Lazy collections have been around for a while in Hibernate, and they are the
most commonly important form of lazy fetching. The children property of the Node class above
is an example of a collection. Lazy (single-point) associations differ from collections by being single
references to other objects persisted by Hibernate. So, the parent property of the Node class
above is an example of an association. They are called single-point associations because if they
were multi-point associations they would be a collection. From now on I'll refer to single-point
associations as just associations, because I'm lazy too. Finally, lazy properties could be values like
name , that are typically mapped to a single column. This is rarely an important feature to enable
(this, unlike other lazy fetching strategies in Hibernate 3, is disabled by default). It even says in
the Hibernate documentation that " Hibernate3 supports the lazy fetching of individual properties.
This optimization technique is also known as fetch groups. Please note that this is mostly a
marketing feature, as in practice, optimizing row reads is much more important than optimization
of column reads. However, only loading some properties of a class might be useful in extreme
cases, when legacy tables have hundreds of columns and the data model can not be improved." .
For that reason I intend to primarily discuss lazy associations and collections, as they are the more
complicated to understand anyway. The same points I'll make here apply for lazy properties as well
For lazy associations to work, the class containing the associations (in this case, the Node class)
must either be a.) represented and retrieved via an interface or b.) not declared as final. This is
instrument the class so that when 'getParent()' is actually called, it can go do the leg work at that
time. It either has to do this through CGLIB, or through dynamic proxies. Dynamic proxies require
an interface; CGLIB requires a non-final class. Note: at the time of this writing, CGLIB is
*significantly* faster than dynamic proxies, but also requires more security access (doesn't like
sandboxes that restrict bytecode modification). So it is a tradeoff. For more information on these
Lazy collections don't suffer from this problem, simply because Hibernate harbors custom
implementations of the java.util.List , java.util.Map and java.util.Set interfaces
(among others) that it sends to your class in place of default implementations (such as ArrayList
).
Atrophied Associations
In general practice, lazy collections and associations are managed by Hibernate transparently, to
the point that you as a developer never have to worry about the fact that objects are only being
loaded 'as you need them'. Unfortunately, one of the most common patterns for Hibernate usage -
inside an MVC web application - trips this transparent wire, setting off an anti-personnel mine of
LazyInitializationException s. Too much ridiculous metaphor? Ok, let's get into the real
example.
In a general-case use, you might have code that looks like this:
efficiently. Unfortunately, the modern pattern of a layered MVC web application causes a conflict
with this. In an MVC web application you may have a servlet like this:
<%
Node node = (Node)request.getAttribute("node");
%>
Name: <%=node.getName()%><br/>
Parent's Name: <%=node.getParent().getName()%><br/> <!-- This line would
cause a LazyInitializationException! -->
As commented in the JSP, calling 'getParent()' on the node will attempt to load the parent node
from the database, but because the NodeDao closed the session as soon as it was done with it, no
further SQL statements can be executed, and Hibernate's proxy around our Node throws a
LazyInitializationException, complaining that we tried to get data that wasn't loaded yet.
4. View requests necessary rendering information from node, such as parent. Exception is
There are really two common answers to this problem as seen by the community right now. The
first is to explicitly initialize all associations and collections required before returning it. The second
is to keep the session open until the view is done rendering (commonly referred to as 'Open
Session In View').
The latter solution (open session in view) typically requires that you have a robust ServletFilter
that *always* closes the Session properly after that view has rendered. From the Hibernate
documentation:
In a web-based application, a servlet filter can be used to close the Session only at the very end of
a user request, once the rendering of the view is complete (the Open Session in View pattern). Of
course, this places heavy demands on the correctness of the exception handling of your application
infrastructure. It is vitally important that the Session is closed and the transaction ended before
returning to the user, even when an exception occurs during rendering of the view. The servlet
filter has to be able to access the Session for this approach. We recommend that a ThreadLocal
variable be used to hold the current Session (see chapter 1, Section 1.4, " Playing with cats ", for
an example implementation).
The example described above is thorough enough that there is no reason to reproduce it here.
Here is the general sketch of a servlet filter using the HibernateUtil class described in the
transparent lazy fetching of the parent in the above example is not done until you are in your view
rendering implementation. That means that if the SQL produced and executed by Hibernate throws
any exceptions, or anything else goes wrong, your view is now responsible for handling it (e.g.
your JSP); and as many of us have learned, one of the key benefits of this 2-step servlet-first
approach is that any errors can be handled by the servlet, which a.) is more succeptible to
pluggable error-handling approaches and b.) is prior to the response being committed, so error
Alternatively, the former solution (don't remember the former solution anymore?) is to pre-load
any resources you know you're going to need in a view. This solution, while being more verbose, is
perhaps more accurate, and provides more control if something were to go wrong. To do this, I
typically still use the HibernateUtil solution. However, closing it as part of the servlet process itself
(rather than through a filter) ensures that the session is out of the picture by the time the view is
rendered. While this doesn't allow the reusability of a filter, most developers now-a-days use an
(org.springframework.web.servlet.HandlerInterceptor), or Struts
behaviors (similar to servlet filters, except only for the controller/action itself), and this behavior
can certainly be done in those. For this simple example, however, I will simply put it in the code.
Then, the trick is to simply initialize any associations required by the view. Simply accessing the
// initialize associations
node.getParent();
request.setAttribute("node", node);
// forward to the JSP
request.getRequestDispatcher("/nodeName.jsp").forward(request,
response);
}
catch(RuntimeException e) {
// handle runtime exception, forwarding to error page, or whatever
}
finally {
HibernateUtil.closeSession();
}
}
}
Note that if we had lazy property association on, we would need to call 'getName()' for the node
Collections require a little more work to initialize - you could of course, do it manually by traversing
the entire collection, but it is perhaps better to call on the Hibernate utility class to do that for you.
The Hibernate.initialize method takes an object as an argument, and initializes any lazy
associations (this includes collections). So, if we wanted to fully initialize our node, and then fully
<%
Node node = (Node)request.getAttribute("node");
%>
Name: <%=node.getName()%><br/>
Parent's Name: <%=node.getParent().getName()%><br/> <!-- This line would
cause a LazyInitializationException! -->
Childrens' Names: <br/>
<%
for(int i=0; i<node.getChildren().size(); i++) {
Node child = node.getChildren().get(i); // generics
if(i > 0) {
%>, <%
}
%><%=child.getName()%><%
}
%>
You would need the servlet (or wherever your object initialization code is) to do a little more
legwork.
// initialize associations
Hibernate.initialize(node);
Hibernate.initialize(node.getChildren());
request.setAttribute("node", node);
// forward to the JSP
request.getRequestDispatcher("/nodeName.jsp").forward(request,
response);
}
catch(RuntimeException e) {
// handle runtime exception, forwarding to error page, or whatever
}
finally {
HibernateUtil.closeSession();
}
}
}
I hope this gives you a starting point for understanding fitting lazy Hibernate collections and
R.J. Lorimer
Contributing Editor - rj -at- javalobby.org
Author - http://www.coffee-bytes.com
Software Consultant - http://www.crosslogic.com