The Hibernate team published the first Hibernate 5 release quite a while ago, and since then they introduced a bunch of new features. I explained several of them here on the blog, and it’s about time to have a look at the most popular ones. Based on the search traffic I get from google and my personal experience, the Java 8 support is the most popular change. But there are also some other features which might seem small but make common development tasks a bit easier.
Support classes of the Date and Time API as BasicTypes
The new Date and Time API was one of the most anticipated changes in Java 8. The old java.util.Date has a lot of issues which got finally fixed.
Unfortunately, JPA 2.1 and Hibernate 4 don’t provide direct support for it. But that’s not a huge issue. It just takes a few lines of code to implement an AttributeConverter that maps a LocalDate.
But obviously, the explicit support as a BasicType is still a lot better. Hibernate implemented that in version 5.0. Since then you don’t need any additional annotations or converter to persist the classes of the Date and Time API. You can use them in the same way as any other supported attribute types.
Get query results as a Stream
Introducing a new method to give you your query result as a Stream doesn’t sound like a big thing. But the stream method of Hibernate’s Query interface provides an additional benefit that makes it especially interesting for huge result sets. It fetches the result set in multiple batches and uses Hibernate’s ScrollableResults implementation to scroll through it. This approach is a great fit if you use a Stream to process the result set records one by one and helps you to implement your use case efficiently.
You can use the new method since Hibernate 5.2 to get your query results. The following code snippet shows a simple example that selects all Book entities from the database and processes them as a Stream.
Fetch multiple entities by their primary key
Fetching multiple entities by their ID is a very common use case. Most developers either implement it with a loop that calls the find method of the EntityManager for each primary key or with a JPQL query that checks all primary key values in an IN clause. The first option requires Hibernate to perform a database query for each primary key. That can create huge performance issues. The second one allows you to fetch all entities with one query and is obviously the better option.
Hibernate 5.1 introduced a third option that avoids the issues of the first and is easier to use than the second one. The new MultiIdentifierLoadAccess interface provides a comfortable option to load multiple entities with one query. You just need to call the byMultipleIds method on the Hibernate Session to get a MultiIdentifierLoadAccess interface and provide a list of primary key values to the multiLoad method
Join unassociated entities in a query
You can easily join mapped associations between entities in JPQL queries. The mapping already provides the required join conditions, and you don’t need to provide them in your query.
But what about entities that map associated database tables but have no mapped association?
And that’s not a rhetorical question.
Most entity models don’t map all the possible associations. They only map the ones that seem to provide value in the domain model and not the ones where 2 database tables (seemingly by accident) store the same foreign key. It also happens quite often that a to-many association with lots of records on the many side doesn’t get mapped with Hibernate. The risk that someone calls the getter of the association and fetches several hundred or thousand entities is just too high.
That’s totally fine as long as you just look at the domain model. You probably don’t need these associations in the model. But that doesn’t mean that you don’t need them in one of your JPQL queries.
If that’s the case, you have 3 options:
- Model the association between the entities or
- Use a cross join in your JPQL query which might create performance issues or
- Use Hibernate’s proprietary JOIN clause.
I prefer option 3. It’s the easiest and most natural one.
Since Hibernate 5.1, you can use an SQL-like syntax to join entities without a modeled association.