Я хочу восстановить после неудачной транзакции.
Теперь, конечно, после любого отката все сущности отсоединяются, а менеджер сущностей закрывается.Тем не менее, пользовательский интерфейс по-прежнему содержит отдельные объекты.Очевидно, что мы не можем просто отбросить изменения пользователя, поэтому мы хотели бы позволить им повторить (исправьте выделенную ошибку проверки, затем снова нажмите кнопку).
После Java Persistence WikiBook ,
Одним из методов обработки ошибок является вызов объединения для каждого управляемого объекта после сбоя фиксации в новом EntityManager, а затем попытка зафиксировать новый EntityManager.Одной из проблем может быть то, что любые идентификаторы, которые были назначены, или версии оптимистической блокировки, которые были назначены или увеличены, возможно, потребуется сбросить.Кроме того, если исходный EntityManager был EXTENDED, все используемые объекты все равно будут отсоединены, и их необходимо будет сбросить.
Сначала эта опция кажется простой, пока мы неизбежно не столкнемся именно с этими ожидаемыми проблемами.,Некоторые службы могут вызывать сброс по различным причинам, что приводит к увеличению полей @Version
как в БД (откат), так и в объектах Java (которых нет).Следующее «сохранение» вызывает merge
, что приводит к неожиданному OptimisticLockException
.
Есть ли надежный способ «откатить» поля версии в бинах сущностей Java?
ОК, швы очень тяжелые.У нас есть каскадные сущности с их собственными @Versions, поэтому выполнение этого вручную кажется хрупким.(Как мы можем достоверно знать исходные (сохраненные) версии в любом случае? Невозможно выполнить запрос, потому что какой-то другой пользователь может успешно обновить сущность в это время; запрос текущей версии может прервать оплокирование!)
Еще один более сложный метод обработки ошибок - всегда работать с нетранзакционным EntityManager.Когда приходит время для фиксации, создается новый EntityManager, нетранзакционные объекты объединяются в нем, и новый EntityManager фиксируется.Если фиксация завершится неудачно, только состояние нового EntityManager может быть непоследовательным, исходный EntityManager останется неизменным.Это может позволить исправить проблему, и EntityManager повторно объединится в другой новый EntityManager.Если фиксация прошла успешно, любые изменения фиксации можно объединить обратно в исходный EntityManager, который затем можно будет продолжать использовать как обычно.Это решение требует значительных накладных расходов, поэтому его следует использовать только в том случае, если действительно требуется обработка ошибок, а поставщик JPA не предоставляет альтернатив.
Это кажется логичным. Есть ли у кого-нибудь опыт реализации такого восстановления с помощью двух EntityManager (особенно в Spring)?Есть ли какие-либо подводные камни, о которых я должен знать, прежде чем пытаться это сделать? Кажется, что каждый сервис и DAO теперь должны были бы узнать о двух менеджерах сущностей (с Spring, сегодня они почти не зависят от уровня постоянства).Операции DAO 'find' используют один EM;«обновление» использует другой.Или используйте отдельные DAO для чтения и записи.Ой.
Другие варианты, которые я рассмотрел, включают:
- Использование DTO в пользовательском интерфейсе, поэтому автоинкремент не влияет ни на что.Ужасно.
- Переместите вызов на
merge
на конец любой составной операции.Объект присоединяется только после успешного завершения всех проверок и обновлений состояния.Кажется странным, что служба «save» больше не будет merge
(только проверка).По сути, пользовательский интерфейс будет нести ответственность за вызов DAO!Это так необычно, как кажется?
Советы? Спасибо: -)
Обновление Моя архитектура включает в себя:
- Отдельные сущности обновляются пользовательским интерфейсом (JSF)
- Идентификаторы сущностей НЕ генерируются автоматически (предварительно назначенные идентификаторы UUID и / или бизнес-ключи)
- Для сущностей автоматически увеличиваются поля
@Version
для оплокирования - Проверка службы «Сохранить», вызовы
em.merge
(JPA через Hibernate) - Проверка службы «Обработка», применение бизнес-логики, обновление состояния объекта
- Услуги могут быть составлены. Одна кнопка пользовательского интерфейса может сделать
- (Spring
@Transactional
совет по контроллеру пользовательского интерфейса: begin )
- Сохранить
- Процесс 1
- Процесс 2
- (
@Transactional
: commit )
- Любая служба может выдать исключительную ситуацию проверки (JSR 303), которая откатывается должным образом (сообщения отображаются в пользовательском интерфейсе)