Атрибут JPA @Version вызывает исключения OptimistLockException при последовательных обновлениях.
Мне не совсем понятно следующее поведение:
Мы берем Entity, куда добавляем@Version
поле для использования оптимистической блокировки спящего режима
@Entity
public class MyEntity {
@Id
@GeneratedValue
public Long id;
@Version
public Long rowVersion;
public String field;
}
Затем мы создаем@QuarkusTest
и проверим, можем ли мы последовательно обновлять и получать объект:
@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);
}
}
Чего я ожидаю:
- Мы сохраняем объект и фиксируем его, устанавливая границу @Transactional.
- Мы извлекаем объект из базы данных с текущей версией строки.
- Обновляем (сливаем) сущность и меняем поле, тем самым увеличивая версию строки в базе данных
- Повторяем 2-3
На самом деле происходит то, что мы можем обновить объект только с первой попытки. Со второй попытки мы, похоже, не получили последнюю версию rowVersion из базы данных.
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]
Почему такое поведение? Разве мы не должны каждый раз получать правильную версию строки из базы данных, поскольку мы работаем за пределами границы транзакции?
Полный источник: https://github.com/arnehehe/jpa-question/tree/main/code-with-quarkus.