3 Reasons to Hate Hibernate
Warning: this is a rant.
This is just a collection of observations of Hibernate, from the perspective of an Oracle developer/”DBA”. I’m aware of some of the benefits of using Hibernate to shield Java developers from having to know anything about the database or the SQL language, but sometimes it seems to me that we might generally be better off if they were required to learn a little about what’s going on “underneath the hood”. (Then I remind myself that it’s my job to help them get the most out of the database the client spent so much money getting.)
So, here are my gripes about Hibernate – just getting them off my chest so I can put them to bed.
Disclaimer: I know every Hibernate aficionado will jump in with “but it’s easy to fix that, all you have to do is…” but these are generalizations only.
Exhibit A: Generic Query Generators
As soon as I’d loaded all the converted data into the dev and test instances, we started hitting silly performance issues. A simple search on a unique identifier would take 20-30 seconds to return at first, then settle down to 4-8 seconds a pop. Quite rightly, everyone expected these searches to be virtually instant.
The culprit was usually a query like this:
select count(*) as y0_ from XYZ.SOME_TABLE this_ inner join XYZ.SOME_CHILD_TABLE child1_ on this_.PARENT_ID=child1_.PARENT_ID where lower(this_.UNIQUE_IDENTIFIER) like :1 order by child1_.COLH asc, child1_.COLB asc, this_.ANOTHER_COL desc
What’s wrong with this query, you might ask?
Issue 1: Case-insensitive searches by default
Firstly, it is calling LOWER() on the unique identifier, which will never contain any alphabetic characters, so case-insensitive searches will never be required – and so it will not use the unique index on that column. Instead of forcing the developers to think about whether case-insensitive searches are required or not for each column, it allows them to simply blanket the whole system with these – and quite often no-one will notice until the system goes into UAT or even Prod and someone actually decides to test searching on that particular column, and decides that waiting for half a minute is unacceptable. It’s quite likely that for some cases even this won’t occur, and these poorly performing queries (along with their associated load on the database server) will be used all the time, and people will complain about the general poor performance of the database.
Issue 2: Count first, then re-query for the data
Secondly, it is doing a COUNT(*) on a query which will immediately after be re-issued in order to get the actual data. I’d much prefer that the developers were writing the SQL by hand. That way, it’d be a trivial matter to ask them to get rid of the needless COUNT(*) query; and if they simply must show a total record count on the page, add a COUNT(*) OVER () to the main query – thus killing two birds with one efficient stone.
Exhibit B: Magical Class Generators (tables only)
Issue 3: No views, no procedures, no functions
When someone buys Hibernate, they might very well ask: is it possible to call an Oracle procedure or function with this product? And the answer is, of course, “yes”. Sure, you can do anything you want!
The day the Java developers peel off the shrinkwrap, the first thing they try is creating a Java class based on a single table. With glee they see it automagically create all the member attributes and getter/setter methods, and with no manual intervention required they can start coding the creation, modification and deletion of records using this class, which takes care of all the dirty SQL for them.
Then, the crusty old Oracle developer/”DBA” comes along and says: “It’d be better if you could use this API I’ve lovingly crafted in a PL/SQL package – everything you need is in there, and you’ll be shielded from any complicated stuff we might need to put in the database now or later. All you have to do is call these simple procedures and functions.” And the Java developer goes “sure, no problem” – until they discover that Hibernate cannot automatically create the same kind of class they’ve already gotten accustomed to.
“What, we actually need to read the function/procedure definition and hand-code all the calls to them? No sir, not happening.” After all, they bought Hibernate to save them all that kind of work, and who’s going to blame them?
So, you say, “Ok, no problem, we’ll wrap the API calls with some simple views, backed by instead-of triggers.” But then they hit another wall – Hibernate can’t tell from a view definition how that view relates to other views or tables.
The end result is that all the Java code does is access tables directly. And you get the kind of queries (and worse) that you saw in Exhibit “A” above.
There. I feel so much better already.
28 November 2011 - 9:01 am
LOL – I can empathize with you, but hate is such a strong word :=)
I have been told that Java developers should focus on Java and not SQL.
28 November 2011 - 2:01 pm
Jeff you are only seeing one side of the coin. Hibernate is a miracle product that allows hardware vendors to meet their earnings targets so their directors can reap millions from their stock options! I’ll bet that ExaData sales people have a list of “things to love about Hibernate” containing your first two items. Query takes 30 seconds? Throw some SSDs and RAM at the problem until either it goes away or the hardware vendor pays off their new corporate headquarters.
As for your third reason – well that is to your benefit. Once the code has all been built as dumbly as possible and there are a series of niggling intermittent bugs because proper APIs weren’t used the desperate client calls in the top gun Oracle DEV/DBA and pays you a ludicrous sum to sort it all out. Rescuing a project after the amateurs have messed it all up – that’s where the big bucks are!
If you stop trying to make efficient use of the client’s resources and just think in terms of maximising waste you’ll come to understand the many and varied advantages of Hibernate. Those SSDs aren’t going to sell themselves you know.
28 November 2011 - 2:31 pm
Thanks Andrew, your words of wisdom have brought much-needed balance to this blog 🙂
30 November 2011 - 10:13 pm
Andrew, that is quite a strong point of view! I’m loving it! 🙂
30 November 2011 - 10:16 pm
Jeffrey, what you say is very true. The best saying to match your feelings is:
“When in Rome, do as the Romans do”
It is hard to understand why Java (PHP / .NET, etc) developers insist on their point of view when switching the language / context / paradigm to SQL. Really incredible, how SQL has been tried to make “undone” by various layers of object-oriented stuff. But what are you going to do? They’re trying to do that to XML as well (e.g. generate WSDL from Java classes. Go figure)…
So I agree with Andrew. With your arcane magic, you know how to deal with the 100k$ Oracle monster. To the rescue! 🙂
30 November 2011 - 10:50 pm
I must mention that I have been lucky enough to work with some very smart Java developers on a current project using Hibernate, who do appreciate the power of the database, and have been willing to listen to me as I rant and rave (and who even agree with me about some of the problems I’ve been talking about).
4 January 2012 - 6:44 am
” I’m aware of some of the benefits of using Hibernate to shield Java developers from having to know anything about the database or the SQL language”
This is not true. Proper Hibernate user needs to be very comfortable with both SQL and JDBC to udnerstand benefits of Hibernate.
Hibernate does so many things right, but it’s more difficult to grasp than it seems. Not knowing Hibernate properly usually results in disaster, but having Hibernate specialist in the team saves so much time of regular developers if they’re told to how to use Hibernate properly in certain situations.
19 April 2012 - 9:29 pm
My main gripe about Hibernate is that HQL imposes a limit on what you can do with SQL. The solution for issue #2 above is not supported by HQL because it introduces an analytic function. I also work with developers that appreciate the power of the database, mostly because they have seen what you can do with SQL (not HQL). Many times I’ve been called to investigate a performance issue and the culprit is a Hibernate generated query. Sometimes changing the HQL around helps generate a better query but sometimes the optimal solution requires using SQL features that are not supported by HQL. Yes, you can replace the HQL with straight SQL but I’ve heard that’s not necessarily as simple as it sounds.
I like to show how much you can do with SQL. I love it when I show developers elapsed time and buffer gets from the original generated query and the same metrics from the new SQL query. It’s great to see developers amazed when they discover how fast the database returns the data they need. I take the opportunity to tell them Oracle does much more than just store data.
19 April 2012 - 9:37 pm
Yes, me too 🙂
So far I’ve found that some query changes are relatively easy for them to retrofit into HQL. For example, if they’ve got a correlated subquery as part of the predicate, they might not be able to roll it into a join to the main part of the query, but they can change the subquery itself – e.g. change from a “WHERE EXISTS ()” into a “WHERE x IN ()”, or vice versa. This sort of simple change is sometimes enough to cause the CBO to find a better plan.
12 July 2012 - 5:12 am
As a Java developer who’s just spent a week trying to find a suitable SQL wrapper library, maybe I can shed some light on the other side of this story.
First of all, the JDBC API is horrible. I cannot emphasise it enough how awful it is. Never mind the simply annoying idiocy of indexing stuff from 1 instead of 0, the fact that it provides no type safety at all is unacceptable in the 21st century. You create a PreparedStatement, you pass it the query string, you compile and build your program…and you still have no idea whether it is syntactically correct! You only find it out when you try to run it and it bombs.
If you’re a lead developer, an additional element of fun is to hunt down all the SQL injection backdoors put in by less experienced colleagues.
And don’t even get me started on BLOB/CLOB handling.
All in all, as a Java developer, this is one of the first things you learn about databases: jdbc.equals( trouble );
As this was pretty much the only way to do SQL for over a decade, it doesn’t take much imagination to see how the leap was made from here to sql.equals( trouble ). We’re talking about nicely written, transient equals() methods here.
Now I was lucky enough to have worked for a company where we had a homebrew SQL wrapper, which limited though (it only called stored procedures), was very good at hiding all the nastiness of JDBC, while keeping us in full control of the actual SQL. But a lot of my fellow Java monkeys weren’t so lucky, so after long years of suffering Hibernate seemed like a godsend. Of course anyone who tried to do more than a hello world with Hibernate soon realises that it isn’t, but, and this is the important thing, it’s still nowhere near as painful as plain JDBC.
Fast forward to two weeks ago, I have to migrate a system from a non-SQL DB to Oracle, I’m desperate for something that will save me the agony of having to work with JDBC. I’ve got a fully fledged object structure and I have a pretty good idea what the database should look like but the mapping between the two is non-trivial and I don’t want to lose control of my queries or change the objects. I knew exactly what kind of tool I wanted but I didn’t fancy my chances of finding one that already exists.
Now that I’ve found jooq and querydsl, life doesn’t look so bad after all. I’m sure that if tools like these two become better known, the number of Hibernate users will drop.
Trust me, not all of us are using Hibernate because we think it’s fun.
14 May 2013 - 5:47 am
Why do an ORDER BY on data you are just COUNTing???
16 May 2013 - 1:37 pm
Ha ha yes – well, that was the least of my worries, since it doesn’t matter either way 🙂