Атрибут 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);
    }
}

Чего я ожидаю:

  1. Мы сохраняем объект и фиксируем его, устанавливая границу @Transactional.
  2. Мы извлекаем объект из базы данных с текущей версией строки.
  3. Обновляем (сливаем) сущность и меняем поле, тем самым увеличивая версию строки в базе данных
  4. Повторяем 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.

0 ответов

Другие вопросы по тегам