-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hibernate dirty checking doesn't work and updates are generated for merged objects which haven't changed #39792
Comments
here is some hibernate trace logging that might help. it clearly states that the object is dirty. this is logging that happens during the second merge, when the object is the same as it is in the database:
|
quarkus-dirty-check-with-vanilla-jpa.zip The above also contains a second test, VanillaJpaTest, which shows that with plain Hibernate 6.4.4.Final (hibernate-core, but I also just tried it with hibernate-graalvm), it works as expected. |
@maxant Thanks for the report. Did you check with this test, which specifically configures Hibernate ORM in a way that is similar to what Quarkus does? If this test fails, then it's a bug in Hibernate ORM that should be reported in the Hibernate Jira -- unless there's already a relevant bug report there, in which case just adding a comment there with your reproducer (and a link to this issue) will be enough. |
Those are all JUnit4 dependencies and I don't have the time to make that work with JUnit5 at the moment. This bug doesn't seem to be known there. Either way, something isn't right, if Quarkus + Hibernate is always generating an update statement, even when the object being merged hasn't changed compared to the database. That is functionality which should work out of the box, and does, as shown by my second test in the second zip above. Maybe it is related to bytecode enhancement. The following image shows the JUnit test where I am just using Hibernate without Quarkus - there are no extra fields on the object: Compare that to when I debug in Quarkus: Either way, it isn't right that the developer needs to first select from the DB and then compare all fields in order to decide if they should call merge or not. Something is definitely wrong here. |
I created this: https://hibernate.atlassian.net/browse/HHH-17917 The fact that it works without bytecode enhancement got me thinking and reading more about it. OK, I updated my second ZIP and added a maven profile to activate bytecode enhancement and sure enough, that is the problem. With it activated, my vanilla hibernate test also fails with the same problem. The first page above, from Vlad it says:
There is no mention of merging, but I guess the problem is, merging doesn't call any setter methods. An alternative approach might be to add a method to my entity class, to manually set all fields given the deserialised DTO (by calling the setters?), but I actually tried that a few days ago and I failed because optimistic locking then no longer worked. |
quarkus-dirty-check-with-bytecode-enhancement.zip Run using |
according to the hibernate bug i posted: this issue should be fixed by hibernate/hibernate-orm#8091 |
Describe the bug
Similar to #30234 but perhaps different.
I have a versioned entity (optimistic locking) which i persist by making a REST call which responds with a JSON representation of that entity. The response contains version 0. I make a change to a field on that JSON and post it back to the server which does a merge. The field is updated in the database and the version is set to 1, which is expected.
I then post the same JSON, and the response contains version 2. I debugged into org.hibernate.event.internal.DefaultMergedEventListener#markInterceptorDirty and it seems to discover that the field has changed, even though the debugger confirms that the values are identical. The methods which hibernate uses at this stage are generated bytecode, so it isn't possible to debug into them.
Using the DirtyCheckInterceptor class posted in the other issue (linked above) solves the problem.
Reproducer: quarkus-dirty-check.zip
I also created a simple unit test which is similar to this article, to check that hibernate doesn't normally update the version number if no fields have changed when merging the object. https://vladmihalcea.com/jpa-persist-and-merge/
Expected behavior
Version numbers should only be updated if a field changes.
More importantly the update sql statement should only be generated if a field changes.
Otherwise merging a tree of objects causes every row to be unnecessarily updated.
Actual behavior
Version and row are updated every time a detached object is merged.
How to Reproduce?
See the reproducer attached above.
Run the GreetingResourceTest, which also contains documentation about what is going wrong.
Output of
uname -a
orver
Linux cronus 6.2.0-39-generic #40-Ubuntu SMP PREEMPT_DYNAMIC Tue Nov 14 14:18:00 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Output of
java -version
openjdk 21.0.2 2024-01-16 OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30) OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)
Quarkus version or git rev
3.9.1
Build tool (ie. output of
mvnw --version
orgradlew --version
)Apache Maven 3.8.7 Maven home: /usr/share/maven Java version: 21.0.2, vendor: GraalVM Community, runtime: /shared2/graalvm/graalvm-community-openjdk-21.0.2+13.1 Default locale: en_GB, platform encoding: UTF-8 OS name: "linux", version: "6.2.0-39-generic", arch: "amd64", family: "unix"
Additional information
No response
The text was updated successfully, but these errors were encountered: