5 Hibernate 5 features every developer should know

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi, I’m Thorben Janssen from thoughts-on-java.org. It’s quite a while since Hibernate 5.0 came out and brought a bunch of changes. And since then the development team implemented even more features. I explained several of them here on the channel and even more on my blog. 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 by far the most popular change. But there are also some other features which might seem small but make common development tasks easier. Let’s begin with the support for the Date and Time API. It 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. I explained that feature in great detail in a previous video. So, let’s take a look at the most important parts and you can watch that video afterwards, if you want to dive deeper. Here you can see a simple entity with attributes of type LocalDate, LocalDateTime, and Duration. All 3 of them were introduced with the new Date and Time API in Java 8. As you can see, I didn’t apply any additional annotations to define the mapping to the database columns. Hibernate already has all the information it needs. As you can see in this test case, you can use these attributes in the same way as any other attributes. I instantiate a new entity, call the setter methods to initialize the attributes and persist the entity. And down here, I use the LocalDate attribute with a bind parameter in the WHERE clause of a JPQL query. Let’s run this test and check how Hibernate handles the attributes of the Date and Time API. The test case was successful. Hibernate mapped the Java types to the correct JDBC types without any additional mapping annotations. It mapped the LocalDate to a JDBC DATE, the LocalDateTime to a TIMESTAMP and the DURATION to a BIGINT. And when I executed the query with the bind parameter of type LocalDate, Hibernate mapped the bind parameter value in the same way. OK, let’s take a look at another addition in Hibernate 5. You can now get query results as a Stream. And I know, introducing a new method to give you your query result as a Stream doesn’t sound like a big thing. You could call the stream() method of the Collection interface to get a Stream with your query results. But the new 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 cases. Let’s jump into the IDE and try it out. The new method is part of Hibernate’s Query interface. That means you can use it with all kinds of projections in JPQL, Criteria and native SQL queries. Here you can see a simple example that uses a JPQL query to retrieve all Book entities from the database. I would expect that this query returns a lot of entities, if you run it on a production database. So, it’s a good idea to not fetch all of them at once to avoid performance issues. But before we use the new stream() method, let’s get the result set as a List, transform it into a Stream and write all entities to the log file. That was the typical approach before Hibernate 5.2 extended the API. As you can see here, Hibernate gets all records of the result set from the database and maps them to entities before it starts processing the Stream. Let’s see how that changes, when I use the stream method of the Query interface instead of the getResultList method. Here you can see that Hibernate’s log messages are mixed with our own messages. Hibernate doesn’t fetch and map all records upfront. It does that only, when the Stream processes the next record. That saves a lot of resources for huge result sets. Let’s get to the next feature. This one is not related to Java 8 but it makes it a lot easier to fetch multiple entities by their primary key. Most developers either implement that 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 that 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. Here you can see the same code as I showed you on the slide. It loads the Book entities with ids 1, 2 and 3. And as you can see in the log output, Hibernate generated only 1 query to get the entities from the database. That’s a lot better than performing a query for each entity and it was much easier than writing the query yourself. This is something I missed for years. Hibernate 5 finally introduced join statements for unassociated entities. In JPA and older Hibernate versions, 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 you can’t do that for unassociated entities. And 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. So, it’s happens quite often, that you could join two tables in a query but you can’t do it with JPQL because there is no mapped association for it. In the past, you either had to add the missing association to your domain model or use a cross join in your JPQL query and hope that the performance wouldn’t be too bad. Since Hibernate 5.1, you finally have a 3rd option. You can join entities without a modeled association in HQL. And as you can see in the code snippet, Hibernate uses an SQL-like syntax for it which makes it easy to use for a lot of developers. Let’s jump into the IDE and check the generated SQL statement for this query. So, here is the same query as I showed you on the slide. It counts the reviews for each book and returns them together with the title. I didn’t model the association between the Book and the Review entity in the domain model. So, I need to define the JOIN clause within the query. Let’s run this test and take a look at the generated SQL statement. Here you can see the SQL query and Hibernate generated the expected SQL JOIN clause based on the provided JPQL JOIN clause. OK and now to the 5th and final feature of this video: @Repeatable annotations. This is another small change that makes working with Hibernate more comfortable. Repeatable annotations are one of the smaller changes in Java 8. It allows you to annotate a class, attribute or interface with the same annotation multiple times. A typical JPA example in which you want to do that is defining multiple named queries for an entity. So far, you had to annotate your entity with a @NamedQueries annotation which contained an array of @NamedQuery annotations. The annoying thing about that is that the @NamedQueries annotation is just a container. It doesn’t provide any value on its own. Since Hibernate 5.2, you don’t have to do that anymore. At least not as long as you use Hibernate’s version of the NamedQuery annotation. @NamedQuery and a lot of other Hibernate annotations are now repeatable and can be assigned multiple times. Isn’t that a lot cleaner and easier to read? OK, that’s it for today. If you want to learn more about Hibernate, you should join the free Thoughts on Java Library. It gives you free access to a lot of member-only content like a cheat for this video and an ebook about the Java 8 support in the Hibernate 5. I’ll add the link to it to the video description below. And if you like today’s video, please give it a thumbs up and subscribe below. Bye!
Info
Channel: Thorben Janssen
Views: 27,528
Rating: undefined out of 5
Keywords: hibernate 5, hibernate, java, jpa, java 8, tutorial, programming, DateTime
Id: bEjKBeB0QKQ
Channel Id: undefined
Length: 12min 54sec (774 seconds)
Published: Wed May 10 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.