Hibernate Dirty-Checking with Converted Attributes

A few days ago I ran into an issue in a rather large application that uses Spring & Hibernate.

I found myself debugging an issue where Hibernate tried to update some entities that I had just deleted, the situation was basically like this:

  1. Load entities A, B, C of type Dummy.
  2. Some logic determines that those entities should get deleted.
  3. Ran a Hibernate CriteriaDelete query which basically did “DELETE FROM DUMMY WHERE ID IN (A, B, C);”
  4. The transaction gets committed and suddenly Hibernate tried to run updates on the entities. This obviously failed since the entities no longer existed in the DB.

Typical reason & how to investigate

By debugging into the Hibernate flushing code I ended up in DefaultFlushEntityEventListener.java:

Snippet from DefaultFlushEntityEventListener.java

What I saw in the debugger here was that Hibernate believed that an attribute of these entities was dirty, interestingly it was an attribute that got persisted via a converter, like this:

@Column(columnDefinition = "VARCHAR")
@Convert(converter = TestDtoConverter.class)
public TestDto getTestDto() {

This made me curious how Hibernate does dirty-checking on attributes that have converters. It turned out that Hibernate makes no difference here between objects with converters and ones without: it simply uses the Object’s .equals method.

The anticlimactic truth

Takeaways

A converter could for example always lowercase a value, so if the value was “asdf” before and we reassign it to “ASDF”, there would be no difference from the database point of view.

However, since Hibernate uses .equals it wouldn’t know that (it doesn’t compare the converters result, but the source object). This makes sense of course, since equals is supposed to be a cheap operation and conversion could be costly. Still, this could be surprising if you didn’t know that.

I’ve created a small test-scenario to play around with this in this github repo/branch.

A related thing to look at would be hibernate custom dirty checking.

Have you run into similar things when using Hibernate with or without converters? Let me know in the comments!

Software engineer from Austria. Passionate about software, likes photography, addicted to podcasts and always busy. http://paukl.at

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store