Should you use JPA for your next project?

This important question gets not asked often enough! And if you don’t think about it, in the beginning, it will be difficult change your mind after the project started.

Most often, the persistence framework gets selected based on personal preferences. And while these are often based on past experiences, it is not always the best approach.

There are 2 main groups of Java developers out there:

The ones who don’t like JPA (or Hibernate as its most popular implementation) because they ran into some issues in the past. Due to this, they don’t want to use it at all.

And then there are the ones who love it and use it in each and every project.

You might expect me to be part of the second group, and that’s not completely wrong. I like Hibernate, but I know that it’s not a good fit for all projects. And as with every tool, it can be really useful or a huge pain, depending on the project or situation in which you want to use it.

So better check your requirements and choose a framework that fits. I prepared a few simple questions to guide you through the decision of choosing JPA or some other persistence framework (please, don’t use plain JDBC).

Do you use a static or dynamic/configurable domain model?

Configurability became a popular requirement during the recent years, and there are some applications out there which have a configurable domain model and store the data in a relational database. I think that a NoSQL database is, in general, the better solution for these applications, but you can also use a relational database for it. But you should NOT use JPA or Hibernate ORM in these kinds of applications.

The acronym ORM, which stands for Object Relational Mapping, already gives a hint that it might not be a good idea to use it with a configurable domain model. And it becomes perfectly clear if I tell you that the mapping definition is pretty static. Technically, it’s possible to adapt the mapping definition, but it creates so many problems, that you should better not try it.

So please, don’t use JPA or Hibernate ORM, if your domain model needs to be configurable.

What is the main focus of your use cases?

OK, if you reach this question, you are using a relational database and a static domain model. So we can finally talk about the use cases you have to implement. For this discussion, I like to group them into 2 categories:

standard CRUD (Create, Read, Update, Delete) operations,

complex reporting and/or data mining related use cases which rely on very complex and advanced queries to retrieve the required data.

If all your use cases fall into the same category, the decision is pretty simple.

JPA and Hibernate ORM are a great fit for standard CRUD operations. They make the implementation of these use cases very easy and efficient. But complex reporting or data mining related use cases are not a good fit because you need to use very complex queries which you can better implement with SQL than with JPQL or HQL.

Complex reporting or data mining related use cases are not a good fit for JPA and Hibernate. You need to implement very complex queries for these use cases, and you should better implement them with SQL than with JPQL or HQL.

But for most applications consist of a lot of different use cases and not all of them fall into the same category. In that case, JPA and Hibernate ORM might still be a good fit if you don’t have to implement too many complex queries. But more about that in the next question.

How many highly complex queries, stored procedures, and custom database functions will you have?

The last question you have to ask is how complex your queries will be and if you have to use a lot of stored procedures or custom database functions.

You might now wonder what makes a query complex and when it becomes too complex for JPA and Hibernate. If that’s the case, your query is most likely not too complex for Hibernate 😉

As a rule of thumb, queries can be implemented in JPQL as long as you don’t need to extensively use sub-selects, complex functions, recursive SQL or database-specific features.

If you have to implement too many of these, you should have a look at other frameworks. Don’t get me wrong; you can, of course, use native SQL queries with JPA and JPA 2.1 added real support for stored procedures and database functions. But there are better ways to do that.
You might want to have a look at frameworks like jOOQ or Querydsl if you have to do a lot of these kinds of queries.

But if most of your queries are not too complex, which is the case for a lot of applications, Hibernate and JPA are a great fit. The advantages of the OR-mapping most often outweigh the disadvantages of implementing a few native queries or stored procedure calls with Hibernate.

Summary and why I didn’t talk about performance

OK, it might seem now that JPA and Hibernate are not a good fit for a lot of projects. And that’s not completely wrong. There are a lot of use cases that can be better implemented with other frameworks.

But in my experience, JPA and Hibernate are still a good fit for most applications because they make it very easy to implement CRUD operations. The persistence tier of most applications is not that complex. It uses a relational database with a static domain model and requires a lot of CRUD operations. As soon as you have implemented that part, you can focus on the business tier which holds the complexity your application has to handle.

And you might wonder, why I didn’t ask any question about performance. The reason for it is, that performance requirements are not a problem if your use cases are a good fit for Hibernate and you have good knowledge about the framework. I collected a few performance tips here and if you want to dive deeper into that topic, have look at my Hibernate Performance Tuning Online Training.

I don’t know of any OR-Mapper that is a good fit for really complex queries. The main issue is that they add an additional layer between the database and your code and that you can’t use the full potential of SQL.
You would need to combine the OR-Mapper with an additional framework like jOOQ for complex queries.

My approach to complex queries is that I try to keep them out of the application code and rather use use-case specific views in the database that I (or a DBA) can then tune as needed.
Those views can then be mapped to generic / view specific read-only entities
which can be queried via simple JPA-QL / native-SQL.
Filter conditions (e.g. where foo = 42) can then be added as needed and will usually be efficiently propagated to appropriate query parts by the the DBMS via predicate push-down.

yes, there are a lot of use cases in which JPA is not the best choice. But you have to keep in mind, that it is a good choice for the most common use cases. That’s probably the best thing you can achieve with any framework.
There are lot’s of options for the other use cases like database-specific drivers for NoSQL databases or maybe Hibernate OGM. And jOOQ is an interesting option for complex queries. It’s provides a DSL on top of SQL.

As you well said, JPA/Hibernate are very good for most of enterprise projects, mainly the ones that are in a green field.

Even if your project has lots of complex reports you can continue using JPA/Hibernate with native SQL to take benefits of its data-mapping. If its native query support it’s not enough you can add another framework to solve this issue, like MyBatis or JOOQ. So you don’t need to give up of JPA/Hibernate just because complex queries, just use both!

Last but not least, another point I think you forgot to talk about has to do with legacy systems and database-based integrations. They have strong influence in your decision! In these cases an ORM like JPA/Hibernate may not be a good choice due to lots of composite keys, lack of normalization, data inconsistency and stored procedures calls. In my opinion you can use another ORM like MyBatis or JOOQ for these use cases.

A combination of Hibernate and a framework like MyBatis or jOOQ can be a good solution as long as both frameworks are used for a good share of the use cases.

Inconsistent and not normalized databases are always a challenge and ORMs are not the main reason for it (at least in my experience). In the ideal world, you can fix the database model to resolve these issues. If that’s not possible, you have to be very careful when you create your entities and decide which columns you have to map and which you should ignore. It’s hard to give a general recommendation for these issues.

Stored procedures do not have to be an issue. JPA supports them since 2.1:
//thoughts-on-java.org/call-stored-procedures-jpa/
//thoughts-on-java.org/call-stored-procedures-jpa-part-2/