Как обнаружить конфликты транзакций с Hibernate? - PullRequest
1 голос
/ 21 сентября 2009

Я использую Hibernate 2.6 с hibernate-entitymanager. Я пытаюсь поймать и обработать ситуации, когда 2 транзакции конфликтуют на объекте. Вот что происходит:

Два потока обновляют один объект с полем @Version. Поток, который теряет коммит-логи гонки, StaleObjectStateException при сбросе. Исключение не выдается, оно просто регистрируется. Я предполагаю, что транзакция помечена только для отката в тот момент.

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

Есть ли способ отловить и обработать такие ситуации в коде? В основном я хочу поймать исключение StaleObjectStateException, но проблема в том, что он не генерируется.

ОБНОВЛЕНИЕ: То, что я пытаюсь сделать с высоты птичьего полета, таково:

У меня есть приложение J2EE, работающее под JBoss. Он имеет некоторые внутренние службы, вызываемые по таймеру, и те, которые вызываются из пользовательского интерфейса. У этого также есть один критический объект. Мне нужно убедиться, что разные потоки не могут обновлять объекты этого класса сущностей одновременно, потому что это может привести к несогласованности данных. Вот почему я реализую оптимистическую блокировку.

Когда возникает проблема с оптимистической блокировкой, я обычно пытаюсь справиться с этой ситуацией. Я хочу поймать его на очень высоком уровне и показать действительное сообщение пользователя (в моем случае самый высокий уровень - это ExceptionMapper for RestEasy). Проблема в том, что когда я ловлю RollbackException, уже слишком поздно.

Я не смываю вручную. Большинство моих EJB-компонентов используют CMT, и сеансы сбрасываются автоматически.

Ответы [ 2 ]

2 голосов
/ 21 сентября 2009

Артем,

Не могли бы вы вкратце объяснить, чего вы пытаетесь достичь? Вид с высоты птичьего полета, очевидно - как этот (вызванный из) код пользовательского интерфейса? Или это процесс на стороне сервера (чтобы у вас был прямой контроль над потоками)? Причина, по которой я спрашиваю, состоит в том, что я (возможно, неправильно) чувствую этот и другие связанные с вами вопросы о том, что вы пытаетесь использовать оптимистическую блокировку для чего-то, для чего она не предназначена, и именно это и вызывает все проблемы.

Что касается StaleObjectStateException, то он определенно генерируется из DefaultFlushEventListener и AutoFlushEventListener, которые обрабатывают явные / неявные сбросы. Вы вызываете flush () вручную? Если нет, возможно, исключение перехватывается / регистрируется кодом обертки при автоматической очистке (Spring? TransactionManager? EntityManager?)

Обновление

Спасибо за разъяснение вопроса. Мне все еще немного неясно, хотите ли вы запретить нескольким потокам из одновременно изменять 1 одной и той же сущности или запретить нескольким пользователям от попытки одновременно отредактировать его.

Прежний сценарий может быть обработан через оптимистическую блокировку; однако без явного flush() он становится недетерминированным (поток, который первым сделал изменение, может не быть сброшен / зафиксирован первым). Смотрите мой ответ на этот вопрос для более подробной информации. Другая проблема с автоматическим сбросом - это то, что вы испытываете в настоящее время - сбой проверки версии не обнаруживается до сброса, и, если этот сброс совпадает с попыткой совершить транзакцию, генерируется исключение RollbackException. В любом случае вся транзакция откатывается.

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

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

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


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

0 голосов
/ 21 сентября 2009

Взгляните на NHProf . Он может помочь вам во всем, что связано с профилированием Nhibernate.

...