Leia em português: clique aqui
If you are creating a new Java project for your REST backend over a relational database, you will probably not even blink before saying: Hibernate. But why? Did you really give a good thought on how this tool actually makes your work easier (or harder)? Did you consider the accurate needs of your architecture and have a good reason to include or not include it?
I'm here to present the good, the bad and the ugly about Hibernate (and ORMs in general), how can it actually hinder your project more than you can even imagine, and of course present an awesome alternative to it.
Let's face it: writing a CRUD in pure JDBC is a huge pain. Hibernate was a ray of light shed on a swampy wasteland. Even in its first version (launched circa 2001), the XML-based mapping was way better than those pesky EJB Entity Beans. It evolved, got annotations, and quickly became the de-facto stardard for any Java application.
Writing a CRUD in Hibernate is pretty fast and quite easy. The complexity only rises as the relationships between your tables also get complex. And this brings us to the next topic:
I'll wrap it up in a single word: mappings. Sure, you have saved a lot of time while writing your CRUD with Hibernate in comparison to writing it on JDBC. But have you calculated how much time you have wasted on Google and Stack Overflow trying to understand why that particular mapping isn't working? And don't be proud of your 15 years expertise mapping knowledge where you just know how to make any kind of mapping, because that junior developer on your team is also struggling and wasting the same amount of time. When two days have already passed and you just can't make that mapping work, you wish you could just write plain SQL and get away with it.
Then again, why not? And this brings us to the worst of it:
Native Queries. Don't lie to me, you just felt shivers running down your spine. Why should you write SQL when you are using a very modern and powerful ORM tool? These little brats break the whole point of using an ORM, not allowing you to switch your database provider for an instance, amongst other bad and nasty things.
Hibernate is all flowers while the project is in the CRUD stage. But when you get to the Reports stage, where you have to create huge joins and subqueries involving lots of tables, things start getting complicated, primarily because of those not-so-neatly resolved mappings. There is not a single Hibernate project I have seen in my whole career that is free of native queries. Someone, in some point of time, didn't have the timespan to be able to do it right, pulled off a little trick and delivered in time. And there was born another native query.
Another ugly almost no one talks about involves performance. I'm not saying Hibernate is slow, but when the DBA comes running from his desk alerting us that a query is degrading the database performance and it needs tunning immediately, we just look at his desperate face and say: "Sorry dude, no tunning for you, its Hibernate, I don't control how queries are made". Then he talks to his manager who talks to your manager and this ends in another native query.
Of course all of this revolves around poor knowledge about creating these mappings. Unfortunately, this is not a simple subject and, at least in my humble opinion, the documentation isn't that clear. I've yet to meet a developer who can fill his chest with pride and say "I can precisely map any relationship you present to me". This only gets worse when the person creating the tables is not the same person who is creating the Java code.
Let's just think a bit about it then. I have saved some time on the CRUD, lost it all or maybe more on the mappings/reports, and then lost all the meaning of it while writing native SQL. What was the advantage in the end? Did using an ORM really paid off? But, if it wasn't that good, then what?
You know Spring, right? Much probably you are already using it on your project. Spring Boot is a fantastic bootstrap for any Java project and it brings a really good amount of functionality to your application. Even if you don't like Boot, just the Spring core itself or even Spring MVC are part of many Java applications today. What if you didn't need to add anything else to be able to do good work with SQL without JPA and without the hurdle of using JDBC directly?
Let's take a look at the Spring Framework documentation, Data Access, chapter 3: Data Access with JDBC. It presents a set of utility classes that abstract all the hard work and leave to you only the actual processing of the data itself. This, coupled with the @Transactional annotation also from Spring, give you an approach very close to what you are used to with Hibernate in terms of automatic transaction control, but without the messy mappings and closer to SQL.
According to this very own documentation, you will only have to:
- Define connection parameters (only once)
- Write queries (selects, mostly)
- Provide parameters
- Process the data retrieved.
You will NOT have to:
- Open/close connections
- Worry about execution details
- Write the loop over every row retrieved
- Commit/rollback transactions and handle exceptions
- Close resources
One of the best classes in this set is the BeanPropertyRowMapper. It can automatically populate a List of POJOs given the columns retrieved in the query are aliased with names identical to the POJO's attributes names. Almost like a mapping, but it does not enforce consistency. For inserts, updates and deletes, you will not even have to write SQL; providing the table name and a Map of column name + value is enough.
I'll not be writing a tutorial for this tiny piece of bliss because this is not the intent with this article. I'm only here to show you there are very good alternatives to a tool that has caused (at least to me) more problems than those it was supposed to solve. I've already wrote a few systems using this approach and my feeling is that in all of them, development regarding database access went much more smoothly than when using Hibernate. I mean, if you are supposed to write a lot of SQL anyway, then why not start out like that already and skip the headaches of having to write concise mappings, all while having the same automatic transaction control?
If you want to jump right in, here's a couple of wrapper classes to get you started:
I'm a realistic person and I wrote this article based on my personal experience over many projects with many different teams using Hibernate. I consider creating mappings way harder than it should be, and also unecessary work when you already know a good amount of SQL. If your project does not have an intensive report generation and/or you're comfortable with ORM mapping, Hibernate is your best choice. Otherwise, I strongly recommend checking out for alternatives. You may find wonderful things outside the mainstream.