Dr. Mindbender, Or How I Learned To Stop Worrying And Love Hibernate

June 7th, 2011 Steve Ayers, Consultant  (email the author)

I’ll admit I was wrong.

For years, I have been beating the drum about town, proselytizing my distaste for Hibernate. I told everyone that would listen what my opinions were. ‘It only gets in the way’, I said. ‘Its too much of a black box’.

And while some of those notions still hold true, I am here today to admit I was wrong in that Hibernate is not a total obstacle of a framework. In the right situations and circumstances, it actually is very nice to have on your side. In the wrong situations, however, it is a nightmare. It is not something that can be forcefed into every situation and while it has its benefits, using it in the wrong project will provide nothing but heartache. Trust me, I know from experience. It is the Dr. Mindbender of frameworks: use it where it should be and it’s a peace-loving orthodontist. Misuse it and you have a hateful, deceitful villain with a proclivity for cybernetics and brain-scrambling.

I spent a decent amount of time on a project that flouted tried-and-true Hibernate conventions. Admittedly, this was my first proper working experience on a major project with it, so naturally, I became prejudiced against it. ‘THIS is what all the Hibernate fuss is about?’, I said, the platform for my future drum-beating beginning to take hold. ‘I know how to write my own database queries, no thanks’.
So from then on, I became a zealot, proudly jutting out my chest in interviews and on projects about how it was worthless, how I’d rather just use easier approaches like Spring and JDBC.

Then, something unexpected happened.

I worked on a project that actually made sensible use of Hibernate. I got to see how a proper persistence-mapping file was created. I saw first-hand some of the benefits of Hibernate that I didn’t even know existed; benefits that weren’t in my egotistical arsenal of query-writing and transactional coding.

But, old habits die hard. In technology, you learn as you go, so it makes no sense to completely flip-flop from one side to another. To be a good developer (to go from journeyman to master, if you will), you should be an amalgam of your experiences. Draw from what you learned and make informed decisions.

So, to prove my point, I will outline the good and the bad of Hibernate. I will tell you when to use it, when not to, and some practices to avoid. And hopefully, you’ll recognize when you should make use of it and when you should avoid it like the plague. After all, there’s a time and place for everything.

The Good

No Query Writing

Probably the biggest and highly-touted feature of Hibernate is that it abstracts the database layer away from the developer. No more fiddling around with DB queries and getting your hands unnecessarily dirty with database connections. Through simple methods such as Session.load() and Session.get(), retrieving an object is simple. In addition, Hibernate’s Criteria API makes complex joins relatively simple and easy to create.

For example, suppose your system has an Order object which has a many-to-one association to a Customer object and the association is by Customer ID. Further suppose that the query to retrieve both orders and customers pits up against two brutally large and inefficiently constructed tables. If you have not specified a fetch strategy on the relationship, the default behavior for Hibernate is SELECT, which means to retrieve an order, two queries will be run: one for the Order and one to populate the Customer association. Normally, what you’d do in plain JDBC world is to simply join these two queries together on the Customer ID, which is a process that can be a pain, especially if the queries are large, the join columns are complex, or the queries are stored in code (requiring a recompile).
However, in Hibernate, you simply change the fetch strategy to JOIN in the mapping file and voila, Hibernate joins the queries together and retrieving an Order runs one query, bringing back Order details and Customer details in one shot.

Caching

Caching is an item that could be its own blog post (I smell sequel!), but I will touch on it here. There are three areas of caching involved with Hibernate: 1st-level, or session-caching, 2nd-level caching, and query caching.

In a nutshell, session caching involves the ability of Hibernate to store objects in cache scoped to the current Hibernate session. What this means in layman’s terms is that the following code:

  Session.load(MyObject.class, 123);
  // Other logic here
  Session.load(MyObject.class, 123);

will only invoke one query for MyObject. The initial invocation hit the database and stored the information in Hibernate’s session cache. Since we are still in the same session, another request for that object will simply retrieve it from the session cache and not pull it from the database.

The second-level cache and query cache work together and are scoped across Hibernate sessions. The 2nd level-cache stores IDs of objects keyed to the respective object values (not the objects themselves). The query cache stores WHERE clauses and their bound parameters keyed to object IDs. Used together they represent a powerful way to improve performance by storing oft-requested information in a cache and minimizing the hits on the database over time. If your application is easily cacheable, then Hibernate could be a good choice for you. It can really speed up response time by eliminating all that expensive database interaction.

So, how do you know if your application has good cache candidates? Well, stay tuned for the sequel. You didn’t learn the back story of Don Corleone in Godfather I did you?

DB From Scratch

One such area that begs for Hibernate is when the database is being designed from scratch. This is not an existing database you are trying to shoehorn Hibernate in front of, this is one that can be designed with an ORM solution in mind. It is one that can be designed for abstractions.

As a result, you can take a more object-oriented approach to fashioning the database and its relationships. You can assure that tables are created that are easily modeled to objects and that the relationships that are defined are properly mapped. If you think in terms of the system and how Hibernate functions, designing the database will be easy and as a result, Hibernate will be a seamless integration into your system.

Lower DB Learning Curve

From a consultant’s point-of-view, it makes it far easier to learn the database and its relationships when a proper and well-documented implementation of Hibernate is in place. Learning database tables and their structures is simple just by scanning the persistence-mapping file. No need looking at cryptic table names and columns where you have to first parse the English translation of them before you can even think of how they all relate together.

Further, the Hibernate entity objects make a developer-friendly way to look at the business model. Everything is laid out into handy Java objects, enabling you to take a more code-centered approach towards learning the domain. In addition, learning data types of fields is extremely easy and all of this makes onboarding that much faster. Which would you rather spend your time learning:

ORD_MASTER

ORD_ID
ORD_NM
CST_ID
QTY
TTL
STS

Or this:

public class Order {
    	private String orderId;
    	
    	private String orderName;
    	
    	private Long customerId;
    	
    	private Integer quantity;
    	
    	private Integer total;
    	
    	private String status;
}

So, while this may not be necessarily a reason to implement Hibernate, it is one positive aspect of it. As a consultant, anything that enables you to learn the client domain faster is a good thing.

The Bad

Query Writing

OK, so maybe I was wrong when I said there’s NO query writing. Sometimes there is. Hibernate has its own query language called the (wait for it) Hibernate Query Language, or HQL. In addition, its syntax is not completely identical to SQL, which I’m guessing is the database language in which you spent a few years dabbling.

Well, they say to learn to new a language once a year, so here’s your newest one. Luckily, you shouldn’t need to use this that often, especially if you have a well-crafted mapping file and make efficient use of the Criteria API. Any ORM worth its salt and that prides itself on database layer abstraction should not force the developer to rely on query-writing, even if it is relatively object-oriented.

Unwieldy Legacy Databases

Legacy databases pose a problem for Hibernate. There are many aspects of a database that can creep in over time and most of them do not react well when an ORM pokes its nose in on their business.

One such sign that Hibernate is a bad idea is business logic in the database, such as in PL/SQL packages and procedures. This type of logic works behind Hibernate’s back and provides nothing but headaches to attached entity objects in your code. For example:

MyObject is retrieved from the database. While it is hydrated, a procedure is invoked in the database that updates a few tables, including the table to which MyObject is connected. Now, your object has stale data inside that it thinks is valid. You now have to flush your object and get the up-to-date data. This kind of thing can be difficult to fix and even more difficult to diagnose.

In addition, with legacy databases, often times developers tend to know the schema and inner workings extremely well. They become intimately familiar with the poor performing tables, where the indices are, and how the relationships work. As such, sticking Hibernate in front of them makes for an extremely problematic transition. They will see Hibernate as a black box obstacle that they have to defer to regarding the database. When you have a group of developers who are used to getting their hands dirty with the data, sticking an ORM framework in their way is going to cause problems.

Unnecessary Information

This item was one of my talking points during my Great Anti-Hibernate Crusade. I’ve grown less vitriolic with this concern in my old age, but its still something I have a bit of trouble with and have never really received a complete and acceptable answer.

Modeling data to objects using an ORM like Hibernate simply returns more data than needed. Period. There are going to be times when you need the values of five columns from a fifty-column table. In addition, this table could have a plethora of one-to-many associations which are fetched eagerly. So, for your five columns you are returning back 47+ values you don’t need and running who knows how many queries needlessly. Sure, you could turn off the eager-loading, but that affects any other logic that needs these associations at the time they’re loaded.

The explanations or resolutions for this I’ve been proposed over the years are that you should design your system in a way where model objects can be used throughout all layers. In a perfect world, that seems reasonable. But user demands are not always reasonable. So, what happens when they request to see a popup on screen showing only those five values from that fifty-column behemoth? Should I tell them I can’t because it doesn’t work well with model objects?

Designing with a model object approach in mind is a great idea with new development, but applying this to legacy code is a headache.

The way I see it, you have three options in the above scenario:

1. Just retrieve the object as its modeled and send the mounds of information back even if its not needed
2. Use a Data Transfer Object
3. Consider a refactoring of the modeling / relationships.

All have tradeoffs and none seem like a silver bullet approach. The last object is probably not going to happen. This is especially true if this is a legacy system with rotting design.

The first option is most likely, but as I said will result in needless data and/or queries being run, but admittedly this is something that could be mitigated with caching strategies.

The second option is sort of like throwing in the towel. Its like admitting you were beaten by requirements. The second you let DTOs creep into the mix, things start to get infected and you’re losing the very foundation on which you built your Hibernate architecture in the first place.

So, that is what I’ve learned so far in my love-hate relationship with Hibernate. I suspect many developers have a love-hate relationship with a lot of tools and mine just happens to be this one. I think it benefits a developer to see the good and bad of each and not just develop unfounded opinions based on one bad experience. That way, they can make an informed decision in any circumstance. Learning to do this allows you to have an open-mind and grow in your knowledge, eventually becoming an evil genius capable of mind control and dentistry, like Dr. Mindbender.

Be Sociable, Share!

Entry Filed under: Agile and Development

11 Comments Add your own

  • 1. Nicolas  |  June 7th, 2011 at 3:43 pm

    I have to disagree on some good points :

    - DB from scratch: for me you should not design your database to fit an object model or to please hibernate. You should design your database as the best way to store your data and think about the relational model.

    Low DB learning curve: you are not limited to 3 characters for column naming you know? Entity relation diagrams exist too and you can make one for all as a documentation if needed. This argument is really a joke!

    No Query Writing: I don’t understand your problem… You say making a join (that’s it A.X = B.Y) in your where clause is difficult ??? Really?

    Recompilation: I do not see the point! If you have encapsulated SQL code in a stored procedure all your need is to run the new SQL. Your JAVA application doesn’t even need a restart for that.

  • 2. Mark  |  June 8th, 2011 at 11:03 am

    Nicholas –

    (DB from Scratch) – Even with with “well defined” database, there is an impedance mismatch with OO. Creating the database from the Object model and THEN refining it is much easier than trying to match the Object model to an existing model. Mainly because people do not understand the implications of their decisions in the relational model. And there are other issues like trying to reverse engineer the db model into an Object model.

    (Low DB Learning curve) – I think the big issue is what people typically do versus what can be done. And there are some naming restrictions in some databases that make things difficult to read/understand. As for ERDs, they only show the relationships between the tables. It does not contain all the documentation needed to understand. And OO model can show the more complex “relationships” (i.e subclasses). Also, with the API documention, i can just look at the classes to find out any additional information and any “hidden” business rules.

    (No Query Writing) – I seldom can get away with not writing any HQL. But with something like QueryDSL I might be able to. Anyway, I think (not sure) the point is that HQL queriers are much easier to write and to understand

    (Recompilation) – I think you misunderstood what he said. As for encapsulated SQL code in a stored procedure – it depends on what you change. You might have to recompile. Anyway, these seldom change “in production” and if you look at the TCO, i would rather restart Java than deal with Stored Procs.

  • 3. Mark  |  June 8th, 2011 at 11:11 am

    Steve, Glad you have come over (mainly) to the dark side. Just a few notes:

    1. DTOs – I think you mean “View Objects” DTOs effectively dead since EJB 1/2 are. Most people are confused as to what they are and how they are used. I dont think there is an official name for what they are but i call them “View Objects” or “Report Objects”.

    2. As for having to do “View Objects”: If you can do session-in-view (which you cannot with detached objects) then you will not be pulling back that much unneeded info (as long as you don’t set all relationships to not be lazy). But if you do, I don’t see this is bad. If you are not using an ORM you still have to do this. And you have to write it all yourself without the benefit of HQL (or JPA or …). I don’t see this as throwing in the towel. Get the attributes of the objects you need and put them in a type-safe object – as a READONLY object.

    BTW, there is a 4th solution – Caching/Data Grid.

  • 4. BB  |  June 8th, 2011 at 2:53 pm

    Your original instincts are more correct than you perceive. Just get into some big project that is trying to scale and use resources efficiently and you will see that Hibernate puts together some of the most god-awful join queries and that in many cases, it is much more efficient to write such queries yourself. I was a huge Hibernate fan and I still like it a lot, but I have come to realize that JDBC is never going away. I would be interested to hear if there are better ways to instruct Hibernate what your expectations are, of course.

  • 5. Steve  |  June 8th, 2011 at 8:58 pm

    Thanks for the comments, everyone.

    Mark – I appreciate the responses. You explained the points better than I probably would have! As for the query writing, I guess I was trying to paint that as a double-edged sword. The point of an ORM is to make that stuff easier, yet, when it comes down to it
    you do still have to write queries sometimes.

    I think we are on the same page with View Objects. They do go by a bunch of names — Data Transfer Objects (DTOs), Transfer Objects, Value Objects, View Objects, etc.

    In the past, on projects that didn’t use any sort of ORM, in my example I would’ve written a super simple query that populated a five field DTO. This just seems to be a corner case where things get a bit difficult with Hibernate. And because this
    was an early experience of mine, it soured me on Hibernate from the get-go. You do make a point that caching could be used although you still have to pull the unnecessary info in the first place to populate the cache.

    BB – Trust me, I know where you’re coming from. Just today I had an issue with Hibernate that I still can’t really explain involving pulling multiple LONG RAW columns from a table. I guess a love-hate relationship like we have isn’t all that bad. You can love it on the projects where its used, and hate it when its not around. A ‘love the one you’re with’ sort of thing.

    Nicolas – I appreciate your responses also and I understand your reactions. I was basically just trying to point out some observations I had and my shock at how I actually started liking something that I had so much distaste for earlier in my career. I won’t belabor the points, though, since Mark wrote an eloquent response.

    Thanks again for the comments. I appreciate everyone taking the time to offer your thoughts. Please keep checking back to the Summa Blog. Great pieces are going up all the time.

  • 6. Sam  |  June 9th, 2011 at 1:34 am

    My biggest dislike points:

    - Hibernate allows you to paint yourself into a corner where you set up your model objects so that you end up getting for example N+1 queries but you have no way of figuring out why.
    - Confusion between hibernate and JPA annotations and how they affect queries
    - It’s hard to get help with hibernate. The forums have a low answer/question ratio and a lot of answers are of the “read the hibernate in action” book variety.
    - Tons of classes to learn about, especially when you factor in Spring’s supporting classes.

  • 7. Mike  |  June 9th, 2011 at 12:51 pm

    Most of the problems you guys refer to with hibernate creating it’s own joins can be easily solved when you understand how hibernate works. You can create a mapping that fits your specific data model better and this should not mimic your database tables. Remember it’s a Mapping not a Copy of the database model. You take one type of data and map it to another. Most people forget this and it’s a really important one.

    Hibernate solves out of the box 80% of your issues. the other 20% yes you will have to do some work and really get to know hibernate but you can make it work.

    When you absolutely cannot solve your issue you can just write straight SQL. Hibernate also provides Transformers which can take the result of that SQL query and map it directly to a pojo. This is exactly what you would have had to do anyway except even here hibernate cuts a step out for you and provides a convenient way of doing that to.

    Hibernate by the way runs on top of JDBC so I don’t see how it’s a replacement.

  • 8. Steve  |  June 11th, 2011 at 8:57 am

    Mike – Agreed on your first point. On the project I referenced that used it incorrectly, our model objects were mapped to the schema exactly. Not only that, but the fields in the objects were named after database tables. So, in your UI layer, you were calling methods like getCdOvLsNm, which was super confusing.

    I don’t think we ever really suggested Hibernate as a way to replace JDBC, just that using straight JDBC and something like Spring was a way to cut out the middle man.

    Sam – The n+1 thing can be a problem. Lazy fetching solves it somewhat, but there are times when this is almost unfixable. Have you tried Stack Overflow with Hibernate questions? Most of what I’m looking for can usually be found there.

  • 9. Jason  |  June 16th, 2011 at 5:58 pm

    You know I started with the assumption that Hibernate would work for 80% of my needs and that I would have to work on the other 20% but then I found out that there was no other 20%. I tend to find the kind of people who hate Hibernate are the same people who think Stored Procedures are the best place to put business logic. It is absolutely just a tool (which works from some use cases and not others), and I wrote my own (flawed) ORM, so I had every reason to believe that only I can solve my own SQL needs. But I came to realize that the team behind Hibernate is just better than me and more focused on the entire component of ORM. I also find that my Hibernate projects have a lot less code in them. Collection classes, DAO patterns are all cruft in a Hibernate project. When I combine Hibernate with Project Lombok the simplicity really shines.

  • 10. Chicken Soup for the Cach&hellip  |  September 12th, 2011 at 9:15 am

    [...] As I mentioned in my last verbose and rambling blog post, this means that: [...]

  • 11. Garvin  |  March 9th, 2014 at 7:46 am

    Frameworks are bad. Bigger frameworks are evil. Fitting a framework to your problem is like fitting an ellipse and a square into a triangle. You probably have been fortunate to get “excellent crafted examples” which suited your need perfectly, thus felt happy. May be you did not need to deviate from those examples. If you deviate even by 10%, you will end up trying to reverse-engineer a meta language trying to see what exactly is it doing behind the screens. That is just plain waste of time. Try to learn SQL. It is direct. It tells you exactly what happens with things. You never need to run one example of SQL in order to understand it. In hibernate you may end up with hundreds of runs/trials trying to figure out what is happening behind the screens.

Leave a Comment

Required

Required, hidden


+ nine = 14

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed

© 2010-2014 Summa All Rights Reserved