Sunday, June 10, 2012

Weaknesses of Hibernate


I would like to know which are the weak points of Hibernate 3. This is not pretended to be a thread against Hibernate. I think it will be a very useful knowledge for decide if Hibernate is the best option for a project or for estimating its time.



A weakness can be:



  • A bug

  • Where JDBC or PLSQL are better

  • Performance issues

  • ...



Also, can be useful to know some solutions for that problems, better ORM or techniques, or it will be corrected in Hibernate 4.



For example, AFAIK, Hibernate will have a very bad performance updating 10000 rows comparing to JDBC in this query:




update A set state=3 where state=2


Source: Tips4all

23 comments:

  1. Hibernate is really great but it definitely needs some skills and experience: knowledge of ORM concepts, mappings and relations are welcome, understanding of how the Session works, understanding of more advanced concepts like lazy-loading, fetching strategies, caching (first-level cache, second-level cache, query cache), etc.

    Sure, when used correctly, Hibernate is an awesome weapon: it's efficient, it will generate better SQL queries than lots (most?) of developers, it's very powerful, it has great performances, etc. However, I've seen many project using it very badly (e.g. not using associations because they were scared to "fetch the whole database" and this is far from the worst horror) and I'm thus always a bit suspicious when I hear "we are doing Hibernate". Actually, in the wrong hands, it can be a real disaster.

    So, if I had to mention one weakness, it would be the learning curve. Don't underestimate it.

    ReplyDelete
  2. I've come off a large project using Hibernate and here are 3 weakness I think Hibernate has

    1. Poor object inheritance handling and an aversion for instrumentation

    When you load an object in Hibernate (and you've used load so it is a proxy), if that object is in reality (as specified by the database) a sub-class of the one you loaded, Hibernate will not load the real type of the object. You will get it as a proxy on the type you asked for when you loaded it (and not a proxy on the actual type of the object). So

    A a = (A) session.load("id", A.class);


    Even if in the database that id is of type B (a subclass of A) you will still only get a proxy onto A (and not B). In order to get the real type you have to do another step.

    This same thing occurs when trawling an object tree.

    Fortunately though, by using instrumentation the trawling issue is solved in that if once an object is instrumented then when trawling the object tree you will get back the real types (except when the object is pulled from a many-to-many collection though).

    Instrumentation does not solve the load anomaly and it still exists, but instrumentation could be used to solve this problem as well.

    2. Save a large new object model in one go

    We had several processes which generated a large amount of new entity objects (persistent objets) and I then needed to save all these. I could not simply call save on the source object and expect everything to be saved. You might ask why I didn't setup the cascading to do this, yes, I could setup the cascading for one of the use cases but then when I ran another one of the process that created new objects that would need its own cascade structure. So I would like Hibernate to have a facility where I can arbitrarily save a set of objects. The work around for this is that I reflectively trawled the object tree calling save on each object, and I had to do this in a particular order. The facility I'm looking for here is called persistence-by-reachability.

    3. Specify the boundaries of what I want prefetched on a task by task basis

    I know with Hibernate you can prefetch a collection via a keyword in a query, often that is not sufficient. Say you want to work with a bunch of related obects, you'd want to have them all pre-fetched up front so no slow down and inefficiency later, furthermore, there may be multiple sets of objects for the various tasks you're looking to perform, all with their own "fetch profile". iow, for this task I want these objects pre-fetched, for that task I want those.

    Fortunately, number 3 is slated for release in Hibernate 3.5 and is known as "fetch profiles".

    ReplyDelete
  3. Hibernate lets you access the underlying JDBC objects, so if there are things you prefer to do in raw JDBC you can (in the same transaction).
    Hibernate supports bulk updates like your example, and they are done directly in the database.


    If you are starting from scratch, hibernate will be great for your project. (Hibernate can be a little difficult if you are reverse engineering an existing db). The philosophy is to let hibernate do everything, and only if you find a bottleneck and find Hibernate is doing less than optimal things, you can try to tweak it or write your query in plain JDBC.

    I think for general projects, Hibernate has no weaknesses against JDBC. And it has several advantages.


    Your app will be cross RDBMS.
    Your app will be safer (Hibernate uses internally prepared queries).
    99% of the time, your app will perform better.

    ReplyDelete
  4. There are some design trade-offs when you're using Hibernate.

    For example you cannot be sure that an object is fully initialized after its constructor is called. Hibernate mandates a default constructor and will initialize your object with successive setter calls. This makes checking invariants harder as you cannot not simply say after the constructor is called I can check the invariants. This has a drastic impact on the domain object design.

    ReplyDelete
  5. "Why does Hibernate try to delete when I try to update/insert?" comes to mind.. The horrors!

    ReplyDelete
  6. All other issue aside, attempting to optimize performance when working with any ORM involves an extra step because the ORM layer translates your query or criterion into SQL which is then executed. Whereas with a direct SQL approach you can tweak the SQL to your heart's content, in ORM systems, you have to tweak your query and hope it has the expected effect on the generated SQL. In my mind this deficit is far outweighed by the benefits of ORM, but its still a failing in my mind.

    ReplyDelete
  7. I've been using Hibernate for around three years. A few things I've found that are rather annoying are:


    It's hard to mix JDBC and Hibernate. They deprecated the connection() accessor. A number of things just can't be done well in Hibernate's HQL.
    It's almost impossible to create insert/select statements that select static strings using parameters to prevent SQL injection. At least, I couldn't figure it out. Something like "insert into foo select 'string',bar,baz from myTable". Such things just don't fit into the ORM model.
    Hibernate Tools is rather limiting if you want to automatically generate your .hbm.xmls or annotated classes directly. Further, you can't mix them to generate the annotated classes and augment that with .hbm.xml stuff, like changing the default key generation method, adding validation, changing select and join modes (to retrieve child notes in a single select instead of hundreds of separate selects) or adding filters.
    There's no good way to mix straight SQL and mapped object access via HQL. Sometimes expressing a query in HQL or Criteria is easier, but you need to wrap that as a sub-select in native SQL due to limitations in HQL. It can be done using internal classes and other hackery, though.
    Calling non-standard SQL functions in HQL is either impossible or very difficult (e.g. newid() in SQL Server.)
    Error recovery is rather poor, at least with SQL Server. Connection's are put into strange states and all subsequent operations fail. It's not smart enough to close the connection to reset. You can somewhat get around this using C3PO, bit it's aggravating none the less.
    It doesn't seem to handle an entity with a subclass. It seems to map the subclass to the base entity and complain that you've already mapped the entity.
    Caching is a blessing and a curse. It sometimes caches aggregate select statements that's obviously uncachable.


    So, while I've definitely saved a ton of development time using it, there have been a number of things that would have been much easier using if it weren't around. Overall, it's been a tremendous time saver.

    ReplyDelete
  8. Its major weakness is that layers such as those "shield applications from underlying DBMS specifics", but that they can only manage to do so at the expense of taking away even more from the power of relational technology for the application, than the average SQL DBMS already does by itself.

    As a prime example, try and find one such layer that doesn't enforce the fallacious and unnecessary notion of "identity" upon the underlying relational stuff.

    That is not a Hibernate 3.0 issue, that is not a Hibernate issue alltogether, that is an issue of people writing and people using such layers who just don't understand jack shit about the power of the relational model.

    EDIT (elaborating on "fallacious notion of identity")

    A database is a set of statements (or "assertions") of fact. E.g. "Mount Kilimanjaro is 5990 metres high" and "I have climbed Mount Kilimanjaro in august, 2008". No database has any need for 37-digit "mount identifiers" in order to be able to (A) represent that information, and (B) allow any user to work with and manipulate that information.

    ReplyDelete
  9. I have been using Hibernate for over 3 years on a project, and I can say that I love it. Yes, it has it's drawbacks. Yes, it does some things inefficiently. However, the few that it does can usually be tweaked out, and in general, especially if you are designing the database yourself, it is wonderful. I have used it for some small personal projects where I was storing data in an embedded Derby database, and I have used it in my current enterprise system I work on.

    The core of Hibernate is it is an abstraction - it frees the majority of your code from having to worry about the database, and allows you to look at the objects themselves, rather than the database calls.

    If you are thinking about using Hibernate, I would strongly recommend the book Java Persistence with Hibernate, written by Christian Bauer and Gavin King. It is not an easy read, very technical, but it covers just about everything there is to know about Hibernate 3. I have a copy near my desk at all times, and it has proven invaluable through my usage of the library.

    ReplyDelete
  10. ORM is ill-suited for tasks where you need to query large, relatively simple datasets and performance matters. The more performance matters, the less useful Hibernate is.

    Example - the Hibernate session. Sometimes I just need to load a huge amount of data from the database and process it a row at a time. Once I am done with the row, I will never access it again. Hibernate adds every row into the session and then checks whether I the object was modified, slowing my code down and running out of memory. If I do not want this behavior, I have to Session.evict the objects, or Session.clear - in other words, I am forced to do extra work to stop Hibernate from doing something I do not care about.

    Another example: When displaying data in a table, you would like the user to choose which columns they want to see.

    How do you make Hibernate load only those attributes of the objects that are actually going to be displayed? Hibernate wants to load the full object, but that means you transfer potentially a lot of extra data that is not needed. This is not necessarily an issue with Hibernate, this is a problem of OOP, which is ill suited to efficiently store certain data structures.

    ReplyDelete
  11. ... better ORM or techniques

    Ebean ORM is session-less ... I believe this makes it much simpler to use and understand than say Hibernate or JPA. You don't have to worry about Session Management (or its side effects) nor lazy loading (which just works).

    You use save() and delete() ... rather than session based merge(), persist(), flush() which is more explicit and gets around issues such as when you only want to flush part of what is in your session etc.

    So, if you want an easier learning curve then Ebean ORM is definately worth a look.

    If you are into performance then I'd suggest "Partial Object" support is also worth looking into (Ebean has partial object support and incorporated it into it's query language).

    ReplyDelete
  12. I found that Hibernate is generally NOT good for batch tasks. I prefer to do them in pure SQL or PL/SQL, evt. with TRIGGERs. Then I call few lines in Java and tadaa - it's done, with no transaction stuff, consistency problems, etc etc.

    I have converted a simple application (properly indexed and mapped) to that approach, and it was 15-times faster after that.

    ReplyDelete
  13. It doesn't seem to be very well supported in terms of fixing bugs. This link put me off
    http://www.theserverside.com/news/thread.tss?thread_id=59963#334556

    ReplyDelete
  14. Views!

    I was surprised by how poor Hibernate's support for views actually is.

    You can specify a table-entity class that will match to a view, add mappings, and it all looks dandy. But when you try to actually using the view in a Criteria-query, such as

    Criteria crit = session.createCriteria(View.class, "view") ...


    you always end up with no results. This forced us to use hand written SQL-queries instead, since that's the only way we could actually get some data from the view;

    String queryString =
    "SELECT " +
    "DISTINCT " +

    ..
    ..

    Query lookupQuery = this.session.createSQLQuery(queryString);

    ReplyDelete
  15. Hibernate is superb and has allowed me to finish mega-projects.

    I dislike the fact that since it automates and hides stuff, the average joe developer will sometimes produce horrible N+1 and other horrendous inefficiencies in his application, something that would naturally not happen when using plain JDBC.

    I also dislike the default constructors and non final fields restriction.

    ReplyDelete
  16. When using hql or criterions, hibernate needs to known how objects are associated together. This can gets tricky if you want generic entities or split your entities in different projects that don't know each others.

    For example, say you have a core module that handles events and events are stored in the database. Over that project, you build an subscriber management module and link events to subscribers. Since the subscription management module depends on the event handling module, you can have a list of events in the subscriber entity but you can't have a subscriber property in the event entity since Event can't depend on Subscriber.

    You can get the list of events for a specific user easily by calling something like subscriber.getEvents() but if you want to query (using hql) for events that are associated to subscribers living in some city, it gets complicated. Using simple SQL, it would be a rather simple query with a join on the join table. Note that you can always fall back to SQL when needed.

    In opposite to what other are saying, I think that inheritance in hibernate is great. Especially when you consider how complex that can becomes. However, you will need to read the doc and experiment with it to really master it.

    Other than that, hibernate is a great tool. I would never start another project using only JDBC.

    ReplyDelete
  17. It seems to have weakness around proxies.

    ReplyDelete
  18. Hibernate always has and probably always will kind of suck at surprisingly obvious things like Java enumerations. To store an enum, you have to go through all sorts of hoops and custom handling classes and whatnots. They should be as simple as integers or strings (depending how you'd like to store them), but for some unknown reason, they're not.

    Also, tuning Hibernate can be rather difficult. Like Rails, it's great to get going, but when it comes to fine tuning, it's not really your friend (although their SQL debug output is fantastic and very useful). Sometimes you want wait an HQL query to do a join, in other cases you want it to retrieve everything from cache, and it's hard to specify when you want what to happen.

    ReplyDelete
  19. I think what you care right now is whether you should use an ORM or not.

    In general terms, Hibernate is a drag if your application logic is very simple in measured in amount of entities and their relationships.

    When you can use ( as you mention )

    update x where y = z

    or

    select * from x

    it is better to use direct SQL or some intermediate step.

    When your entities relationship are too complex ( like

    select x.a, y.b from j,k,l,m,x,y where j.id = k.id and k.id = x.id and ..... )

    it is better to use an ORM.

    See this other answer for more details on that

    ReplyDelete
  20. Lack of foundation? Here is my experience with TopLink (and I wonder if Hibernate is any different):


    Extract a subset of attributes from one relation. Really easy mapping; move on.
    Extract data spread between two relations. TopLink: "here is dozen-something different types of relationship..."


    Game over. I'd rather learn 7 classic relational algebra operations, rather than 13 proprietory ad-hock association types. I'm a little facetious, of course: I knew relational algebra and SQL pretty well at the time, so there is really little motivation to learn an alternative way.

    ReplyDelete
  21. "So forgetting the Hibernate, JDBC and everything else for a second; how do I find out what mountains I have climbed in August, 2008 that were above 3000 meters high?"

    RESTRICT(JOIN(MOUNTAINHEIGHTS,MYCLIMBS),AND(EQ(CLIMBDATE,...),GT(MOUNTAINHEIGHT,___)))


    in which ... stands for the appropriate value selector for "august 2008", and _ stands for the appropriate value selector for "3000 metres height".

    MOUNTAINHEIGHTS and MYCLIMBS are the relvars ("tables" if you need that term).

    And the join between the two works because obviously, (a) both have a mountainname, and (b) the database is such that there cannot be any climbs of a mountain that does not exist (assuming that if a mountain exists, its height is known).

    INCIDENTALLY

    "his points and counters are all valid".

    I have not seen any "points and counters", and therefore must admit to the truth of this statement : every predicate is always true over the empty set.

    ReplyDelete
  22. It seems to me that it is not possible to follow a "code-first" development approach with Hibernate. See this question here on SO:

    "is-there-some-tools-to-implement-code-first-approach-on-android"
    (The problem/answer is not specific to android, as the title suggests)


    Java does not support the Lambda syntax that makes a lot of these fluent API's possible.


    related: does-fluent-hibernate-exist

    ReplyDelete
  23. its a nightmare to do optimization on a project where you use reverse engineering. You have to reapply all your tweaks whenever you regenerate your mappings. If you don't use reverse engineering , creating your own mappings is not a cake either

    ReplyDelete