I don't quite understand the following behaviour:
We take an Entity where we add a @Version
field to use hibernate's Optimistic locking
@Entity
public class MyEntity {
@Id
@GeneratedValue
public Long id;
@Version
public Long rowVersion;
public String field;
}
We then create a @QuarkusTest
and test if we can consecutively update and fetch the entity:
@QuarkusTest
public class RowVersionTest {
@Inject
EntityManager em;
@Test
public void testRowVersion(){
MyEntity entity = createEntity();
Long id = entity.id;
for (int i=0; i < 10; i++){
MyEntity entityById = getById(id);
entityById.field += i;
System.out.println("Before: " +entityById.field + " - RowVersion: " + entityById.rowVersion);
update(entityById);
System.out.println("After: " +entityById.field + " - RowVersion: " + entityById.rowVersion);
}
}
@Transactional
public MyEntity createEntity() {
MyEntity newEntity = new MyEntity();
newEntity.field = "Hello";
em.persist(newEntity);
return newEntity;
}
public MyEntity getById(Long id){
TypedQuery<MyEntity> query = em.createQuery("Select e from MyEntity e where e.id = :id", MyEntity.class);
query.setParameter("id", id);
return query.getSingleResult();
}
@Transactional
public void update(MyEntity entity){
em.merge(entity);
}
}
What I would expect to happen:
- We persist the entity and commit by setting the @Transactional boundary
- We fetch the entity from the database with the current rowversion
- We update (merge) the entity and change the field, thereby increase the rowversion in the database
- We repeat 2-3
What actually happens, is that we are only able to update the entity the first try. On the second try, we don't seem to get the latest rowVersion from the database
Before: Hello0 - RowVersion: 0
After: Hello0 - RowVersion: 0
Before: Hello01 - RowVersion: 0
jakarta.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [org.acme.MyEntity#1]
Why is this behaviour? Shouldn't we get the correct rowversion from the database every time, as we are running outside of Transaction boundary?
Full source: https://github.com/arnehehe/jpa-question/tree/main/code-with-quarkus