|

5 Reasons and 101 Bugfixes – Why You Should Use Hibernate 5.3


Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.


Hibernate 5.3 is available for a little more than 3 months now, and last week, the team released the 3rd maintenance release. So, it’s about time to take a closer look at the new version.

In addition to more than 100 bug fixes, Hibernate 5.3 includes a few features and improvements that might motivate you to update your current project.

Improved Memory consumption

Let’s start with probably the best reason to update to Hibernate 5.3: It consumes less memory than the previous versions.

The improvement was triggered by an interesting discussion in the Hibernate forum. A user reported that he tried to migrate his application from Hibernate 3.6 to 5.3. During the migration, he recognized that the memory consumption of Hibernate’s SessionFactory went up to 950MB.

The issue was caused by the size and number of EntityLoaders that Hibernate instantiated. It was fixed in 2 steps:

  1. HHH-12556 – Similar EntityLoaders now share some internal data structures. This reduced the memory consumption of the application by ~50%.
    The fix was backported to Hibernate 5.2.18. So, if you’re using Hibernate 5.2 and don’t want to upgrade to 5.3, you should at least update to 5.2.18.
  2. HHH-12558 – Hibernate supports a bunch of different lock modes with specific loaders. In the past, it instantiated all loaders eagerly. Hibernate 5.3 only instantiates the 2 most common ones and loads all others lazily.

At the end of the discussion, the user who reported the issue wrote that the improved Hibernate version only used ~ 250MB. So, for his application, these two changes reduced the memory consumption by ~70%.

I obviously can’t promise that it will be equally effective for your project. However, the reported improvement is so enormous that you should at least give it a try.

JPA 2.2 compliance

Hibernate 5.3.0 is the first version that’s fully compliant with JPA 2.2. However, because the support for all the interesting features was already added in Hibernate 5.0, 5.1 and 5.2, and I already wrote extensive tutorials about all of them, I will not dive any deeper into this topic.

If you’re not already familiar with JPA 2.2, you can read more about it in the following articles:

Small Improvements

Implicit ID generator definitions

If you generate your primary key values, you’re probably aware of Hibernate’s @SequenceGenerator and @TableGenerator annotations. You can use them to define which sequence or table Hibernate shall use to generate the primary key value.

Here is a typical example of a primary key mapping that tells Hibernate to use the database sequence author_seq to generate the unique primary key values.

@Entity
public class Author {

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "author_seq")
	@SequenceGenerator(name="author_seq", sequenceName = "author_seq")
	private Long id;

	...
}

The mapping definition consists of 2 parts:

  1. The @GeneratedValue annotation defines which generation strategy Hibernate shall use and references a custom generator.
  2. The @SquenceGenerator annotation specifies the generator and tells Hibernate the name of the sequence you want to use.

As you can see in the code snippet, I use the same name for the generator and the database sequence. That’s a pretty common and verbose mapping.

If your mapping looks the same, I have good news for you: You no longer need to define the generator if your database sequence or table has the same name as your @SequenceGenerator or @TableGenerator.

That enables me to shorten the previous mapping and to remove the @SequenceGenerator definition.

@Entity
public class Author {

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "author_seq")
	private Long id;

	...
}

Support for MySQL 8 SKIP LOCKED and NOWAIT

MySQL 8.0.1 added the SKIP LOCKED and NOWAIT feature to provide different options to handle locked rows during read-operations. The MySQL Server team explained them in great detail on their blog: MySQL 8.0.1: Using SKIP LOCKED and NOWAIT to handle hot rows.

Here’s a quick description of both features:

  • SKIP LOCKED enables you to perform a non-deterministic read that skips all locked rows. That means that locked rows are missing in your result set.
  • If you require a deterministic read but don’t want to wait for the locks to be released, you can use the NOWAIT feature. It causes your query to fail immediately if any records in your result set are locked.

The MySQL8Dialect included in Hibernate 5.3 supports both these features so that you can use them in your queries.

Apply AttributeConverter when calling a function

AttributeConverters provide a standardized, easy way to define the mapping of a Java type. You can either use them to add support for unsupported classes or to customize the mapping of an already supported Java type.

The following code snippet shows an example from my JPA Tip: How to map a Duration attribute. JPA 2.2 doesn’t provide a mapping for java.time.Duration objects. If you want to map such an object, you can use this AttributeConverter to map it to a Long.

@Converter(autoApply = true)
public class DurationConverter implements AttributeConverter<Duration, Long> {
	
	Logger log = Logger.getLogger(DurationConverter.class.getSimpleName());

	@Override
	public Long convertToDatabaseColumn(Duration attribute) {
		log.info("Convert to Long");
		return attribute.toNanos();
	}

	@Override
	public Duration convertToEntityAttribute(Long duration) {
		log.info("Convert to Duration");
		return Duration.of(duration, ChronoUnit.NANOS);
	}
}

After you applied the AttributeConverter to an attribute or automatically applied them to all attributes of a specific type, it gets transparently used:

  • during all lifecycle state transitions,
  • to map the result of a query and
  • when used in path expressions in a JPQL or CriteriaQuery.

However, for whatever reason, the usage of converted attribute values as function parameters is explicitly undefined.

Previous Hibernate versions didn’t convert the attribute value if you referenced it as a function parameter. This changed with Hibernate 5.3.2. It now converts the attribute value before it provides it as a function parameter.

Support for Java 9 and preparations for Java 11

Beginning with Hibernate 5.3.0, all Hibernate modules specify a Java 9 module name following the pattern org.hibernate.orm.${module-name}, e.g., the hibernate-core module defines the name org.hibernate.orm.core.

The Hibernate team also updated the dependencies, prepared the build process and run their test suite with the latest JDK 11 build. So, we can hope for a smooth transition to JDK11.

Conclusion

Should you update to Hibernate 5.3?

You probably already know my answer. It’s a clear yes! Especially the improved memory consumption is a great reason to do the update.

However, please keep in mind that every update has its risks and that you obviously shouldn’t update any project dependency without testing it carefully.

So, what about you? Did you already update your application to use Hibernate 5.3 or will you update it in the near future?

4 Comments

  1. Hi Thorben,

    thank you very much for your article.

    I would like very much to use this release, but I am constrained to use spring boot.
    Do you know by any chance which spring boot/spring data jpa is picking up this release?

    Thank you in advance,
    Dragos

  2. hibernate 5.2.18 is not still out

    1. Avatar photo Thorben Janssen says:

      Hi Marc,

      it will be the next release. Just be a little patient 😉

      Regards,
      Thorben

Comments are closed.