2014-02-04 3 views
8

У меня есть метод, аннотированный с @Transactional. Я извлекаю объект из своего БД, меняю поле и возвращаюсь из метода. Без сохранения моего объекта база данных все равно обновляется, что странно.Почему @Transactional автоматически сохраняет базу данных

Не могли бы вы рассказать мне, как избежать этого beahvior?

+0

Что происходит, если метод * не * транзакционный? –

+0

Мне действительно нужно @Transactional, чтобы избежать LazyInitializationException – Rachidon

ответ

8

Это поведение является одной из основных целей транзакционной деятельности.

Прежде чем транзакционный метод вот-вот вернется, транзакция совершает, то есть все изменения управляемых объектов будут сброшены в базу данных.

Если произошла ошибка, транзакция будет отменена, что означает, что в базу данных не будут внесены изменения.

Возможно, вы пытаетесь получить LazyInitializationException при попытке доступа к лениво загруженному свойству, вероятно, к коллекции из объекта. Ленообразные свойства не генерируются при получении из базы данных.

Если вы получаете доступ к лениво загруженному свойству в транзакции, поставщик сохранения будет создавать запрос, создать экземпляр результата и прикрепить его к «родительскому» объекту.

РЕДАКТИРОВАТЬ: Если вы хотите, чтобы ленивые свойства были загружены, и иметь возможность изменять вашу сущность без сохранения изменений в БД, вы можете получить сущность с объединениями для получения для ленивых свойств.

em.createQuery("SELECT e FROM MyEntity e JOIN FETCH e.lazyProp"); 

Далее следует один из способов, описанных в @orid.

Если вы не используете извлечение соединений, вам нужно будет получить доступ к лениво нагруженным свойствам в то же время внутри транзакции:

myEntity.getLazyProp().size(); 

Обратите внимание на вызов size(). Вызов получателя недостаточно, так как вы получите прокси. Вам необходимо выполнить операцию, которая требует фактических данных из свойства.

+0

Очень хорошо положил. У вас есть предложения по справочным материалам по этой теме? –

+0

Спасибо, Кевин.Единственным ресурсом, который я могу порекомендовать, является [Pro JPA 2 Book] (http://www.apress.com/9781430219569), так как это то, что я использовал для изучения JPA. Глава 6, EntityManager/Управление транзакциями, вероятно, лучшее место для поиска. Те же знания, вероятно, можно найти в документах Hibernate и Eclipselink. – kostja

+0

Спасибо kosjta за ваш ответ очень полезный, у меня была в голове идея, что без вызова данных обновления не будет передано DB. Еще раз спасибо :) – Rachidon

6

Это нормальное поведение JPA.

Как только вы получаете объект через find() или около того, этот объект считается прикрепленным или принадлежит контексту персистентности. Как только вы выходите из метода, @Transactional запускает аспект управления транзакциями Spring, который сбрасывает каждый «грязный» объект в базу данных и совершает транзакцию. Поскольку ваш объект уже изменен в контексте контекста персистентности и транзакции, изменения сохраняются в базе данных даже без необходимости явного вызова метода сохранения.

Если вы хотите изменить свой объект, не затрагивая базу данных, у вас есть два варианта:

  1. обновить поле после возвращения из метода с аннотацией @Transactional
  2. Если жгуты метода, вызовите detach на руководитель предприятия
+0

Спасибо за ваш ответ, теперь я понимаю, как это работает;) – Rachidon

 Смежные вопросы

  • Нет связанных вопросов^_^