Upgrading to Hibernate 3 – a war story

I finally got a chance to try out upgrading to Hibernate 3 at work. It wasn’t the smoothest of rides, but I got there in the end.

First, some background: the project I’m working on has about 40,000 lines of production code. There are about 100 mapped Hibernate classes. This isn’t small by any means.

The upgrade process went as follows:

  • Drop in the new version of Hibernate, and the support files that I needed (antlr, asm, cglib, dom4j, commons-collections and commons-logging). Hunting down which ones I needed to update was painful, but that was more due to the project structure than anything to do with Hibernate.
  • Do a quick “search-and-replace” for ‘sf.net.hibernate’ to ‘org.hibernate’. Fixed up a handful of changed packages manually (e.g. net.sf.hibernate.expression to org.hibernate.criterion)
  • Changed the cache provider to be the Hibernate-supplied version of EHCache
  • Compile, and be amazed at how many times we used the “old” ways of querying and deleting[1]
  • Fix all of those. This was fairly mechanical, and I’ll elaborate later.

At this point I had a clean compile, and I was ready to run my unit tests. And that’s when I started hitting issues. So here’s the list:

  • There were a lot of classes with private zero-arg constructors, especially on dependant or releated objects. None of these would load in Hibernate 3. The reason, as it turns out, is that classes are now “lazy-loaded” by default in Hibernate 3; that is, the object is used as its own proxy. Previously, the default was no proxy and non-lazy. Lazy loading is good, but it meant that you needed constructors that were at least package-level; private constructors don’t work for some reason. I had about 20 of these, and I couldn’t find an explanation anywhere; eventually, I logged it as a bug, and Gavin King gave me the explanation. Almost invariably, BTW, I want the lazy-load behaviour; I’ll live with package-level zero-arg constructors (though I would prefer private).
  • Loading my mapping configuration took ages; creating a configuration and session factory went from ~25 seconds to about 2 minutes. This had me puzzled, but hunting around the Hibernate forum lead me to this post Sure enough, I’d forgotten to update the DTD line in the configuration and mapping file and the delay was caused by repeated resolution of the DTD. This was followed by much self-kicking. Remember to update your mapping files to use the right DTD! (With the right DTD, it took about 16 seconds)
  • I had some broken HQL around deletes; it turns out that the Hibernate authors had decided to drop support for aliases in HQLs for delete. So delete from Foo foo where foo.active = false doesn’t work while delete from Foo where active = false does. Personally, I found this really annoying.
  • There’s bugs in the HQL parser around the use of static constants In the Hibernate 3.0 release, java.lang.Character constants aren’t inserted in the HQL correctly. *[Fix will be released in 3.0.2]*
  • Deleting entities in one-to-many or many-to-many relationships didn’t work because Hibernate didn’t delete the related rows
  • Deleting subclasses didn’t work at all some sort of HQL parser error. *[Fix was released in 3.0.1]*

Due to these issues, I’ve put on hold any further investigation into upgrading Hibernate until they’re resolved. OTH, they do get resolved fast: the HQL with characters constants had a (partial) fix the next day (thanks Gavin).

My recommendation: try it and see. There’s a lot of promise, it’s mostly stable, and the Hibernate folks do push bug fixes out fast. If you hit a problem, report it and get it fixed.


[1] The find(), delete(), etc, methods on Session

Author: Robert Watkins

My name is Robert Watkins. I am a software developer and have been for over 20 years now. I currently work for people, but my opinions here are in no way endorsed by them (which is cool; their opinions aren’t endorsed by me either). My main professional interests are in Java development, using Agile methods, with a historical focus on building web based applications. I’m also a Mac-fan and love my iPhone, which I’m currently learning how to code for. I live and work in Brisbane, Australia, but I grew up in the Northern Territory, and still find Brisbane too cold (after 22 years here). I’m married, with two children and one cat. My politics are socialist in tendency, my religious affiliation is atheist (aka “none of the above”), my attitude is condescending and my moral standing is lying down.

14 thoughts on “Upgrading to Hibernate 3 – a war story”

  1. Um, no Christian, they’re not really, with the exception of the DTD one, which was my oversight. At best, there’s a throw-away reference with no real mention of the cost (e.g. the reference to classes being lazy by default is there, but no mention of what a class being lazy actually means). In other cases, I found out the information after scouring the forums (for example, the fact that aliases are not supported in delete or update queries anymore, having been dropped in a release candidate)

    The first list is how far the migration guide (which is mostly excellent, BTW). The second list is the problems I had.

    Feel free to quote the guide to prove me wrong, however. Or better yet, please take this feedback from someone who read the migration guide (which is a work in progress, after all) in detail, and update it to help other people not encounter these issues.

  2. Actually, 3, 5, and 6 are nothing to do with the upgrade to HB3, since they refer to new functionality that did not exist in HB2. 3 and 5 are *not* bugs, they are correct behavior as per JSR-220. 6 is a bug that existed in 3.0final and that was *already fixed and released* in 3.0.1 when you submitted your bug report to JIRA and wrote this blog entry.

    1 and 2 are, IMO, very adequately covered in the Hibernate documentation and migration guide. Since you ask for it, here is the quote: “Update the DTD reference in your hbm XML files. Change http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd to http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd in the DOCTYPE.”

    4 was an actual bug in the new query parser that is now fixed in CVS. (Use of Character-valued rather than String-valued constants in HQL is a somewhat obscure case.) Clearly, you could have worked around this problem by following the advice of the migration guide that “if you have problems with the new query parser, switch back to the classic parser with a property setting”.

    Really, I think the tone of this blog entry is quite unfair.

  3. I hate wasting my time like this, but here you go:

    1. In reference documentation for years, proxies need package visible constructors _always_. This is nothing new or underdocumented by any means.

    2. Clear in migration guide.

    3. We didn’t drop aliases! We implemented a completely new functionality called Bulk update/delete, for EJB3. Documentation for this can be found in the EJB3 specification drafts (and a pointer to this in the latest Hibernate reference docs, for all who don’t read API docs).

    4. Yeah, a bug.

    5. Again, this is a new feature for which you did not read documentation. It works as expected even if this is not what you need.

    6. Known limitation of a new feature, always documented in JIRA, now in 3.0.1 also in the reference docs.

    Instead of ranting on your blog, why not post a comment on the migration guide page if you still feel something is missing?

  4. Have you guys been drinking the JBoss Kool-Aid? I did not see this post at all as a negative rant, but rather as a useful bit of information. I’ve been toying with the idea of upgrading on several projects but wanted to hear about some real experiences first. This was a great step in that direction. The author also took a pretty positive outlook towards Hibernate. To call it a rant is a bit paranoid, distasteful, and quite frankly, not what I would have expected from either of you (based on everything I’ve read in the past).

  5. I agree that this was not a rant.

    I disagree that this was an accurate representation of the difficulty of migrating to HB3 (given that half the listed issues relate to a feature – bulk delete – that did not exist in 2.1), and one is explicitly documented in the migration quide. And I disagree that “mostly stable” is a fair characterization of the current release. (Yes, of course some new functionality has bugs, but all HB2 functionality, including the classic query parser is still there and very stable.)

    I dunno, I always get suspicious (and yes, a bit “paranoid”) of people posting semi-accurate stuff in blogs. There are, IMO, other more constructive places such as the Wiki – in this case, comments on the migration guide page would be very much appreciated.

  6. Gavin,

    I see bulk delete as an enhancement of the Session.delete method that was deprecated. In fact, the way I migrated was to change calls like this:

    getSession().delete(“Foo”);

    to:

    getSession().createQuery(“from Foo”).delete();

    When I find the behaviour has changed substantially, above and beyond the documented performance improvement, I call that an issue to be aware of. As the migration guide explictly states to use DELETE queries instead of the delete method, I felt that this was a stumbling block.

    Not a problem: a stumbling block. That is, a change in behavior that suprised me, which I didn’t feel (for whatever reason) adequately aware of, and which I didn’t expect. That’s why I called it an issue.

    (Oh, and I agreed that the DTD thing was my snafu)

  7. Oh, and for some reason, my login to the Hibernate forum doesn’t work for the Hibernate wiki – so no commenting possible.

  8. Christian: you dropped support for aliases. In a pre-release version, update and deletes had support for aliases. The release didn’t. There’s even posts about it on the forums.

    In implementing this “brand new feature”, you deprecated similar (but _not_ equivalent) features. The delete() method on Session understood aliases. This made it really easy to share common HQL.

    Now, you have support for aliases everywhere that HQL is used, _except_ in executeUpdate().

    Oh, and as was seen with the subclasses problem (apparently fixed in 3.0.1 – I said you guys were fast!) you had code still in the system that was expecting aliases.

    Again, this was an issue for me. I meant I couldn’t simply do a quick search-and replace for the delete() method to change it to the new calling style: I had to sit down and modify each delete call so that the HQL would work. And there was no hint in the migration guide that I would need to; in fact, there was the strong implication that the queries would be easily migrated.

  9. Gavin,

    You took me to task on one of the bug entries about being annoyed that I have to go off and read the EJB3 documentation to understand how Hibernate works. Your exact quote was “You are using free software. You have no right to get annoyed about *anything*. End Of Conversation.”

    In general, I agree. However, at the same time, you don’t have the right to complain about the fact that I published my opinions and experiences (which were not overly negative) in a forum outside of the approved venue of the Hibernate forums or Wiki. It goes both ways.

Leave a comment