Как обнаружить конфликты транзакций с 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. В любом случае вся транзакция откатывается.

Последний сценарий (не позволяющий пользователям редактировать) НЕ может быть обработан оптимистической блокировкой. Вместо этого вам нужно будет реализовать пессимистическую блокировку - либо на уровне базы данных, либо на уровне приложения. Другими словами, процесс таков:

  1. пользователь хочет редактировать объект
  2. проверить, существует ли блокировка на объекте
  3. ДА - запретить редактирование (разрешить просмотр только для чтения?)
  4. NO - заблокировать объект, разрешить редактирование
  5. зафиксировать (отменить) изменения; снять блокировку

Не забудьте истечь существующие блокировки после определенного периода бездействия пользователя, если вы используете этот подход.


одновременное изменение1 в данном случае не совсем точно (для этого нужны транзакции); мы говорим о том, чтобы не допустить перезаписи одним потоком правок другого на основе более старой версии.

Посмотрите на NHProf. Он может помочь вам со всеми видами вещей, связанных с профилированием Nhibernate.

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