JPA Callbacks

53534733В статье о управлении сущностями в JPA я писал, что с точки зрения у каждая управляемая EntityManager сущность имеет строго определённое состояние и строго определённые правила перехода из состояния в состояние (если углубляться в теорию, то речь идёт о конечном автомате). В так же предусмотрен сравнительно несложный механизм обратных вызовов (callbacks) из EntityManager в те моменты, когда он меняет состояние сущностей. Это позволяет разработчику управлять процессом перехода сущности из состояния в состояние и реализовывать дополнительный функционал, например проверку уровней доступа, учёт обращений, ведение истории изменений и так далее. Идеологически механизм JPA callbacks похож на механизм событий в Hibernate.

Callback может быть определён как в классе сущности, так и в отдельном классе, связанным с классом сущности. Я использую модель данных из статьи о управлении сущностями в JPA и добавлю в неё обратные вызовы:

В классе сущности я определяю только один callback, вызываемый после загрузки сущности. Тип вызова задаётся аннотацией @PostLoad. Все остальные callbacks определены в классе OperationListener, с которым сущность Operation связана с помощью аннотации @EntityListeners.

Всего, как следут из кода выше, есть 4 типа callbacks, три из которых вызываются до и после изменения.

  • @PrePersist — вызывается как только инициирован вызов persist() и исполняется перед остальными действиями.
  • @PostPersist  — вызывается когда сохранение в базу завершено и оператор INSERT выполнен.
  • @PreUpdate  — вызывается перед сохранением изменений в сущности в базу.
  • @PostUpdate — вызывается, когда данные сущности в базе обновлены и оператор UPDATE  выполнен.
  • @PreRemove — вызывается как только инициирован вызов remove() и исполняется перед остальными действиями.
  • @PostRemove — вызывается, когда операция удаления из базы завершено и оператор DELETE выполнен.
  • @PostLoad — вызывается после загрузки данных сущности из БД.

Стоит отметить, что помеченные @Pre функции вызываются всегда, когда вызывается метод, инициирующий изменение состояния сущности. В то время как @Post вызываются только тогда, когда операция уже была выполнена. И если операция не выполняется, то @Post метод не будет вызван. Например, если вы изменяете значение нескольких полей в сущности, а потом её удаляете вызовом remove(), то будет @PreUpdate  метод будет вызван несколько раз, @PreRemove и @PostRemove будут вызываны по одному разу и @PostUpdate может быть не вызыван ни разу.

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

Код примера доступен на github.