Как обнаружить конфликты транзакций с Hibernate?
Я использую Hibernate 2.6 с hibernate-entitymanager. Я пытаюсь поймать и обработать ситуации, когда 2 транзакции конфликтуют на объекте. Вот что происходит:
Два потока обновляют один объект, который имеет поле @Version. Поток, который теряет коммит-логи гонки, StaleObjectStateException при сбросе. Исключение не выдается, оно просто регистрируется. Я предполагаю, что транзакция помечена только для отката в тот момент.
После этого, когда поток пытается выполнить фиксацию, происходит сбой с RollbackException. Я не нашел способа узнать в коде, почему транзакция откатывается.
Есть ли способ поймать и обработать такие ситуации в коде? В основном я хочу поймать исключение StaleObjectStateException, но проблема в том, что он не брошен.
ОБНОВЛЕНИЕ: То, что я пытаюсь сделать с высоты птичьего полета, заключается в следующем:
У меня есть приложение J2EE, работающее под JBoss. Он имеет некоторые внутренние службы, вызываемые по таймеру, и те, которые вызываются из пользовательского интерфейса. У этого также есть один критический объект. Мне нужно убедиться, что разные потоки не могут обновлять объекты этого класса сущностей одновременно, потому что это может привести к несогласованности данных. Вот почему я реализую оптимистическую блокировку.
Когда возникает проблема с оптимистической блокировкой, я пытаюсь справиться с этой ситуацией в целом. Я хочу поймать его на очень высоком уровне и показать действительное сообщение пользователя (в моем случае самый высокий уровень - это ExceptionMapper for RestEasy). Проблема в том, что когда я ловлю RollbackException, уже слишком поздно.
Я не смываю вручную. Большинство моих EJB-компонентов используют CMT, и сессии очищаются автоматически.
2 ответа
Артем,
Не могли бы вы вкратце объяснить, чего вы пытаетесь достичь? Вид с высоты птичьего полета, очевидно - как этот (вызванный из) код пользовательского интерфейса? Или это процесс на стороне сервера (чтобы у вас был прямой контроль над потоками)? Причина, по которой я спрашиваю, состоит в том, что я и (возможно, неправильно) чувствую этот и другие связанные с вами вопросы о том, что вы пытаетесь использовать оптимистическую блокировку для чего-то, для чего она не предназначена, и именно это и вызывает все проблемы.
Так далеко как StaleObjectStateException
идет, это наиболее определенно выбрасывается из обоих DefaultFlushEventListener
а также AutoFlushEventListener
которые обрабатывают явные / неявные сбросы. Вы вызываете flush() вручную? Если нет, возможно, исключение перехватывается / регистрируется кодом обертки при автоматической очистке (Spring? TransactionManager? EntityManager?)
Обновить
Спасибо за разъяснение вопроса. Мне все еще неясно, хотите ли вы предотвратить одновременное изменение несколькими потокамиодной и той же сущности или запретить нескольким пользователям одновременно редактировать ее.
Прежний сценарий может быть обработан через оптимистическую блокировку; однако без явного flush()
это становится недетерминированным (поток, который сделал модификацию первым, может не быть сброшен / зафиксирован первым). Смотрите мой ответ на этот вопрос для более подробной информации. Другая проблема с автоматическим сбросом - это то, что вы испытываете в настоящее время - проверка сбоя версии не обнаруживается до сброса, и, если этот сброс совпадает с попыткой совершить транзакцию, генерируется исключение RollbackException. В любом случае вся транзакция откатывается.
Последний сценарий (не позволяющий пользователям редактировать) НЕ может быть обработан оптимистической блокировкой. Вместо этого вам нужно будет реализовать пессимистическую блокировку - либо на уровне базы данных, либо на уровне приложения. Другими словами, процесс таков:
- пользователь хочет редактировать объект
- проверить, существует ли блокировка на объекте
- ДА - запретить редактирование (разрешить просмотр только для чтения?)
- NO - заблокировать объект, разрешить редактирование
- зафиксировать (отменить) изменения; снять блокировку
Не забудьте истечь существующие блокировки после определенного периода бездействия пользователя, если вы используете этот подход.
одновременное изменение1 в данном случае не совсем точно (для этого нужны транзакции); мы говорим о том, чтобы не допустить перезаписи одним потоком правок другого на основе более старой версии.
Посмотрите на NHProf. Он может помочь вам со всеми видами вещей, связанных с профилированием Nhibernate.