Optimistic locking @Version annotation causes spurious update on merge() of detached objects ( but not saveOrUpdate() ) when nothing has changed

Description

A simple Parent -> Child with @OneToMany children.

If have a detached object that has zero changes from the previously saved object and you call session.merge() a spurious update is generated if the Parent has an optimistic locking @Version field.
However, no spurious update is generated if :

  • There is no @Version field

  • session.saveOrUpdate() is used instead of session.merge()

Here is the std-out to kind illustrate the issue. Note the update statement.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ******** SAVE session.save() Hibernate: select child2x_.id, child2x_.name as name2_1_ from Child2 child2x_ where child2x_.id=? Hibernate: select child2x_.id, child2x_.name as name2_1_ from Child2 child2x_ where child2x_.id=? Hibernate: insert into ParentWithOptimisticLocking (name, VERSION, id) values (?, ?, ?) Hibernate: insert into Child2 (name, parent_id, child_index, id) values (?, ?, ?, ?) Hibernate: insert into Child2 (name, parent_id, child_index, id) values (?, ?, ?, ?) ================================================= Parent table after save ================================================= ID NAME VERSION 2b9ec59dabec4d6bad35bab64b9229ce barry 0 ================================================= ******** SAVE OR UPDATE THAT DOESN'T UPDATE Hibernate: select parentwith_.id, parentwith_.name as name2_2_, parentwith_.VERSION as VERSION3_2_ from ParentWithOptimisticLocking parentwith_ where parentwith_.id=? Hibernate: select child2x_.id, child2x_.name as name2_1_ from Child2 child2x_ where child2x_.id=? Hibernate: select child2x_.id, child2x_.name as name2_1_ from Child2 child2x_ where child2x_.id=? ******** GET BY ID Hibernate: select parentwith0_.id as id1_2_0_, parentwith0_.name as name2_2_0_, parentwith0_.VERSION as VERSION3_2_0_, children1_.parent_id as parent_i3_1_1_, children1_.id as id1_1_1_, children1_.child_index as child_in4_1_, children1_.id as id1_1_2_, children1_.name as name2_1_2_ from ParentWithOptimisticLocking parentwith0_ left outer join Child2 children1_ on parentwith0_.id=children1_.parent_id where parentwith0_.id=? ******** MERGE THAT SHOULDN'T UPDATE Hibernate: select parentwith0_.id as id1_2_1_, parentwith0_.name as name2_2_1_, parentwith0_.VERSION as VERSION3_2_1_, children1_.parent_id as parent_i3_1_3_, children1_.id as id1_1_3_, children1_.child_index as child_in4_3_, children1_.id as id1_1_0_, children1_.name as name2_1_0_ from ParentWithOptimisticLocking parentwith0_ left outer join Child2 children1_ on parentwith0_.id=children1_.parent_id where parentwith0_.id=? Hibernate: update ParentWithOptimisticLocking set name=?, VERSION=? where id=? and VERSION=? ================================================= Parent table. The version appears to have updated ================================================= ID NAME VERSION 2b9ec59dabec4d6bad35bab64b9229ce barry 1 =================================================

Here is Test case

Environment

None

Status

Assignee

Unassigned

Reporter

Superbazza

Fix versions

None

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

5.4.2
5.4.0

Priority

Major