JPA/@PostPersist @PostUpdate - транзакция

В настоящее время я работаю с @PostPersist и @PostUpdate, и в этих триггерах я сохраняю дополнительные сущности. Вопрос в том, являются ли эти триггеры в одной и той же транзакции, и если нет, то можно ли ее принудительно заставить?

Для меня это работает так. Пока я просматривал журналы, транзакция не существует (она запускается непосредственно перед запуском триггера), что мешает мне (без REQUIRES_NEW для сохраняющегося метода из вложенного bean) сохранить дополнительные объекты в базе данных. Атрибут REQUIRED полностью игнорируется, а атрибут MANDATORY не генерирует исключения.

Может ли быть проблема с JUnit (поскольку я нахожусь в dev-фазе и не тестировал поведение на полном env.)?

Если расширение транзакции по этим триггерам невозможно, как обеспечить, чтобы, если откат происходит до @PostPersist и @PostUpdate, эти операции также будут отменены.

Заранее спасибо за любую помощь,

С уважением, Р.

Ответ 1

Увольнение события PostPersist не означает, что объект совершил успешную фиксацию. Сделка может быть отменена после запуска события, но до успешного совершения. Если вы в PostPersist получите менеджер сущностей, используемый в транзакции, а затем выполните некоторые действия следующим образом:

@PostPersist
void someMethod() {
  EntityManager em = null;
  em = getEntityManagerUsedInTransaction();
  EntityTransaction et = em.getTransaction(); // should return the current transaction
  if (et.isActive() ) {
    // do more db stuff
  }
}

NB: Я не пробовал это, так что это только предположение (tho 'Я использовал экстренный запуск события для жизни для других вещей). Я должен добавить, что я не думаю, что это хорошая идея. Используйте PostPersist, чтобы отметить, что другие объекты должны сохраняться и выполнять их в другой транзакции.

Ответ 2

Если вы используете Spring, вы всегда можете зарегистрировать TransactionSynchronization с вашим текущим менеджером транзакций, чтобы быть вызванным на события, такие как фиксации вашей текущей транзакции:

@PostPersist
void onPersist() {
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {

      @Override
      public void beforeCommit(boolean readOnly) {
        // do work
      }
    });
  }    
}

A TransactionSynchronization также обеспечивает обратные вызовы после успешной транзакции и до/после завершения транзакции.

Если вам нужно проверить, была ли транзакция выполнена или откат, используйте afterCompletion(int status).

Подробнее см. TransactionSynchronization JavaDoc.

Ответ 3

JPA Внутренние методы обратного вызова Внутренние методы обратного вызова - это методы, которые определены в классе сущности. Например, следующий класс сущности определяет все поддерживаемые методы обратного вызова с пустыми реализациями:

@Entity
public static class MyEntityWithCallbacks {
    @PrePersist void onPrePersist() {}
    @PostPersist void onPostPersist() {}
    @PostLoad void onPostLoad() {}
    @PreUpdate void onPreUpdate() {}
    @PostUpdate void onPostUpdate() {}
    @PreRemove void onPreRemove() {}
    @PostRemove void onPostRemove() {}
}

Внутренние методы обратного вызова всегда должны возвращать void и не принимать аргументы. Они могут иметь любое имя и любой уровень доступа (открытый, защищенный, пакетный и закрытый), но не должны быть статическими.

Аннотации указываются при вызове метода обратного вызова:

@PrePersist - before a new entity is persisted (added to the EntityManager).
@PostPersist - after storing a new entity in the database (during commit or flush).
@PostLoad - after an entity has been retrieved from the database.
@PreUpdate - when an entity is identified as modified by the EntityManager.
@PostUpdate - after updating an entity in the database (during commit or flush).
@PreRemove - when an entity is marked for removal in the EntityManager.
@PostRemove - after deleting an entity from the database (during commit or flush).

Класс сущности может включать методы обратного вызова для любого подмножества или комбинации событий жизненного цикла, но не более одного метода обратного вызова для одного и того же события. Тем не менее, тот же метод может использоваться для нескольких событий обратного вызова, отмечая его более чем одной аннотацией.

По умолчанию метод обратного вызова в классе супер сущности также вызывается для объектов сущности подклассов, если этот метод обратного вызова не переопределяется подклассом.

Ограничения реализации Чтобы избежать конфликтов с исходной операцией базы данных, которая запускает событие жизненного цикла объекта (которое все еще выполняется), методы обратного вызова не должны вызывать методы EntityManager или Query и не должны обращаться к каким-либо другим объектам объекта.

Если метод обратного вызова создает исключение в активной транзакции, транзакция отмечена для отката и больше не задействованы методы обратного вызова для этой операции.