Steps to reproduce:
1. Open Entity Manager (in my case , it is Open Entity Manager in View)
2. Start TX
3. Lock an Entity with LockModeType.OPTIMISTIC_FORCE_INCREMENT
4. The entity has some JSR 303 annotation (For example @NotNull). Change the entity in a way that the validation mus fail
5. Commit the transaction. That fails with an Exception containing the JSR303 ConstraintViolation. So far, everything is as expected.
6. Open a new Transaction (same entity manager). The transaction is set "readOnly" in Spring.
7. Do some query for a completely different entity.
8. Commit Transaction.
9. The version of the entity, that has been locked in the first TX is increased now! In the SQL log one can see the according update statement. -> Bug
10. Close the entity manager.
After some debugging I found out, that locking the entity creates an EntityIncrementVersionProcess which is usually executed when JdbcTransaction is in "beforeTransactionCommit".
However, if the flush fails in JdbcTransaction.beforeTransactionCommit, the EntityIncrementVersionProcess is not processed (which is okay) and stays in the queue (which might be not okay ?).
So, after the first transaction failed, the second will execute the EntityIncrementVersionProcess (that was created during first TX) and thus it will increase the version of the entity.
From JPA specification, I am not really sure if the version of the entity must be incremented in TX 2 or not.
But with Hibernate it depends on the outcome of the first TX (ConstraintViolationException or not?) whether the version of the entity is incremented in the second TX or not.
IMHO, that's wrong.
Spring ORM, MySQL