Проблема транзакции в спящем режиме - PullRequest
1 голос
/ 28 октября 2008

Мы используем Hibernate Spring MVC с фильтром OpenSessionInView. Вот проблема, с которой мы сталкиваемся (псевдокод)

transaction 1 
load object foo
transaction 1 end

update foo's properties (not calling session.save or session.update but only foo's setters)

validate foo (using hibernate validator)
if validation fails ?
 go back to edit screen
 transaction 2 (read only)
 load form backing objects from db
 transaction 2 end
 go to view
else 
transaction 3 
session.update(foo)
transaction 3 end

проблема в том случае, если проверка не пройдена foo помечается как «грязный» в сеансе гибернации (поскольку мы используем OpenSessionInView, у нас только один сеанс в запросе http), когда мы загружаем объекты поддержки формы (например, список некоторых сущностей, использующих запрос HQL), переходите в спящий режим перед выполнением запрос проверяет, есть ли в сеансе грязные объекты, он видит, что foo есть, и сбрасывает его, когда транзакция 2 фиксируется, обновления записываются в базу данных. Проблема заключается в том, что, хотя это транзакция только для чтения и хотя foo не была обновлена ​​в транзакции 2, hibernate не знает, какой объект был обновлен в какой транзакции, и не сбрасывает только объекты из этой транзакции. Какие-либо предложения? кто-нибудь сталкивался с подобной проблемой до

Обновление: этот пост проливает свет на проблему: http://brian.pontarelli.com/2007/04/03/hibernate-pitfalls-part-2/

Ответы [ 6 ]

1 голос
/ 15 июля 2009

Здесь проблема дизайна. Как вы думаете, ORM - это прозрачная абстракция вашего хранилища данных, или вы думаете, что это набор библиотек для манипулирования данными? Я бы сказал, что Hibernate является первым. Вся его причина существования заключается в том, чтобы убрать различие между состоянием объекта в памяти и состоянием базы данных. Он предоставляет низкоуровневые механизмы, позволяющие вам разделить их и разобраться с ними по отдельности, но тем самым вы удаляете большую часть ценности Hibernate.

Так что очень просто - Hibernate = ваша база данных. Если вы не хотите, чтобы что-то сохранялось, не меняйте свои постоянные объекты.

Проверьте ваши данные перед обновлением объектов вашего домена. Обязательно проверяйте и доменные объекты, но это последняя линия защиты. Если вы получаете ошибку проверки постоянного объекта, не проглатывайте исключение. Если вы не предотвратите это, Hibernate сделает правильную вещь, то есть закроет сеанс тут же.

1 голос
/ 31 октября 2008

Здесь есть несколько вариантов. Во-первых, вам фактически не нужна транзакция 2, так как сеанс открыт, вы можете просто загрузить вспомогательные объекты из БД, что позволит избежать грязной проверки сеанса. Другой вариант - удалить foo из сеанса после его получения, а затем использовать метод session.merge () для его повторного подключения при сохранении изменений.

В hibernate важно понимать, что именно происходит под одеялом. На каждой границе фиксации он будет пытаться сбросить все изменения объектов в текущем сеансе независимо от того, были ли внесены изменения в текущую транзакцию или в какую-либо транзакцию вообще по этому вопросу. Таким образом, вам не нужно вызывать метод session.update () для любого объекта, который уже находится в сеансе.

Надеюсь, это поможет

1 голос
/ 28 октября 2008

Вы можете запустить get on foo, чтобы поместить его в сеанс гибернации, а затем заменить его на объект, который вы создали в другом месте. Но чтобы это работало, вы должны знать все идентификаторы для ваших объектов, чтобы идентификаторы выглядели корректно для Hibernate.

0 голосов
/ 24 ноября 2009

Реализация сервисного уровня, взгляните на аннотацию Spring @Transactional и отметьте ваши методы как @Transactional (readOnly = true), где это применимо.

Ваш режим сброса, вероятно, установлен на автоматический режим, что означает, что вы на самом деле не можете контролировать, когда происходит фиксация БД.

Вы также можете установить ручной режим сброса, и ваши службы / репозитории будут пытаться синхронизировать БД с вашим приложением, только когда вы скажете им об этом.

0 голосов
/ 29 ноября 2008

А как насчет установки singleSession = false в фильтре? Это может привести к тому, что ваши операции будут разделены на отдельные сессии, поэтому вам не придется иметь дело с проблемами с кешем 1-го уровня. В противном случае вы, вероятно, захотите отсоединить / прикрепить ваши объекты вручную, как предлагает пользователь выше. Вы также можете изменить FlushMode в своем сеансе, если вы не хотите, чтобы вещи очищались автоматически (FlushMode.MANUAL).

0 голосов
/ 16 ноября 2008

А как насчет использования Session.clear () и / или Session.evict ()?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...