Hibernate/JPA and myBatis Considered

At the last SeaJUG, I mentioned that I was really impressed with the latest myBatis (the successor to iBatis), and that it might be more appropriate for many projects than Hibernate/JPA. I've gotten very, very deep on Hibernate, and so I think a few people were rather surprised to hear me speak so favorably about myBatis. First, a bit of background. I started working with Hibernate really early, back in 2001-200, and I wrote a book on Hibernate in 2004. I've worked with many developers and projects that have used Hibernate (and a few NHibernate) over the years. In the summer of 2010, I served as a technical expert in a patent case that involved Hibernate.

First, the brief version: HIbernate/JPA is great if you have a small, very senior team of developers who really understand Java, SQL, and ORM very, very well. For a mid-to-large team with more than a few junior developers, Hibernate/JPA is a Really Bad Idea. For many situations and environments, myBatis is much more appropriate.

Ok, if you're still reading, you may be interested in "the long version." Here are a few more thoughts:

  • Using Hibernate/JPA properly requires understanding Java and SQL very well. If you use Hibernate to avoid learning SQL, you will be miserable and your app will perform poorly.  If it's a toy app, it doesn't really matter.
  • Using Hibernate/JPA properly requires learning HQL and/or Criteria and paying attention to the generated SQL. To get that working, you need to spend time setting up your environment and tools correctly.
  • Hibernate/JPA is so much better than EJB 1.x-2.x it's a no-brainer. That's actually not a huge compliment, alas.
  • Someone asked about "legacy" Hibernate.  I personally define legacy code as code without a good test suite, regardless of framework.  Certainly an application based on Hibernate 3.x+ should not be considered legacy just because of that.
  • Spring Transaction Annotations + Hibernate/JPA = almost always a terrible idea. Just use the open-session-in-view if you are building a web app. You will get much better performance, avoid lots of dumb lazy-loading exceptions, and automatically map transactions to web requests (which is almost always the transaction you want anyways).
    • Incidentally, Grails transactions defaults to basically an auto-commit=true model, but adds a one-liner to turn on transactions in an open-session-in-view model.  There is a debate going on about changing this.
    • Play Framework defaults to open-session-in-view transactions.
  • You can have an excellent (or terrible) app in any framework. It's almost entirely a product of the development organization and has nothing to do with the framework.
  • The learning curve for myBatis is practically nil compared to Hibernate/JPA. You don't have to worry about bad code nearly as much, because the SQL is so much more in your face. The new annotions in myBatis (vs. XML config in iBatis) make myBatis really, really nice and easy. The real kicker for me is (as Eelco mentioned) being able to develop the query quickly in your database tool and then just paste it in as an annotation in myBatis. Simple and easy.
  • myBatis is more or less useless if you want to maintain simultaneous database independence.  If you are working on in-house apps, you probably don't care about switching out databases - and if you do want to switch databases, it'll be an event, which you can still manage via iBatis.  Hopefully you have a good test suite.
  • Hibernate/JPA is fantastic if you want to support multiple databases simultaneously. For example, you are working on a commercial product that needs to supports multiple RDBMS packages. Set up a build that targets all of the supported databases and you're good to go. This does require a good test suite and a solid commitment to TDD - not typical junior dev territory.
  • Hibernate has a really rich 2nd level cache ecosystem (part of what makes it the leading contender for JPA). If you don't care about (or more commonly, don't understand) that, it just makes stuff more complicated.
  • If you use JPA or if you use myBatis, I would recommend an explicit cache (e.g. as I talked about in my session) if you care about performance.  It's more straight-forward and much easier for everyone to understand.
  • If you are using lots of native SQL (or stored procedures) do not use HIbernate/JPA, period. You're missing the whole point. Use myBatis and you will be much happier.
  • JPA is a (popular) standard. If you want to be a credible senior Java developer in 2011, you should be really comfortable with Java, SQL, and JPA. Having an opinion is one thing, but it should be an informed opinion.  "Hibernate/JPA/myBatis sucks" is not an informed opinion.
  • Hibernate/JPA/myBatis absolutely can scale. None of these bring scale for free, all of them can be screwed up badly, all of them can be used in highly scale solutions. If you don't have a real performance test environment, where you conduct real (verifiable, fact-based) performance tests, you're just expressing opinions.

As a corollary: if you are working in an environment that does not respect and encourage senior developers to take ownership, you will have problems. Put another way, if you hear that a company is having a lot of problems with Hibernate, that's a good sign that the company is having trouble hiring/keeping good senior developers. But that's another topic...