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

Мы работаем над небольшой сетью (будет работать на Tomcat) со слоем данных, созданным с помощью JPA (Eclipselink). Я сделал нечто подобное некоторое время назад. Но я всегда не был уверен, когда мне нужно начинать и заканчивать транзакции или выполнять сброс. На данный момент я использую транзакцию, если добавляю (сохраняю) и удаляю объекты. Если я вызываю сеттеры для уже сохраненного объекта, я не использую транзакции.

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


person dermoritz    schedule 10.02.2014    source источник


Ответы (1)


Я думаю, что можно обобщить ответ на ваш вопрос. почти для любой операции JPA требуется транзакция, за исключением поиска/выборки, которые не блокируют объекты (т. е. любая операция JPA, которая не изменяет данные).

(Диспетчер сущностей в области транзакции JTA) В случае диспетчера сущностей в области транзакции JTA лучше цитировать из спецификации (Глава 3 Операции сущностей):

Методы persist, merge, remove и refresh должны вызываться в контексте транзакции, когда используется диспетчер сущностей с контекстом сохраняемости в области транзакции. Если контекст транзакции отсутствует, создается исключение javax.persistence.TransactionRequiredException.

Методы, задающие режим блокировки, отличный от LockModeType.NONE, должны вызываться в контексте транзакции. Если контекст транзакции отсутствует, создается исключение javax.persistence.TransactionRequiredException.

Метод find (при условии, что он вызывается без блокировки или вызывается с LockModeType.NONE) и метод getReference не требуется вызывать в контексте транзакции. Если используется диспетчер сущностей с контекстом сохраняемости в области транзакции, результирующие сущности будут отсоединены; если используется диспетчер сущностей с расширенным контекстом сохраняемости, они будут управляться. См. раздел 3.3 об использовании менеджера сущностей вне транзакции.

(Диспетчер сущностей, управляемый приложением/локальный ресурс) В случае диспетчера сущностей, управляемого приложением, спецификация JPA не дает четкого представления о поведении. В случае Hibernate довольно сложно, что происходит, когда не внутри транзакции (это может зависеть также от драйвера JDBC и режима автоматической фиксации соединения с БД). Прочтите статью Hibernate по этой теме. Настоятельно рекомендуется всегда использовать транзакции для вышеупомянутых операций.

Ко второй части вашего вопроса: если вы вызвали сеттер управляемого объекта и без сброса отсоединили его (т.е. до фиксации транзакции), поведение непонятное/неопределенное, т.е. вам лучше исправить код.

Пример глючного кода:

//begin Transaction
MyEntity entity = em.find(MyEntity.class, 1L);
entity.setField("New value");
em.detach();//it is not sure whether the "New value" will be persisted. To make sure it is persisted, ypu need to call em.flush() before detaching
//commit Transaction

Обычно, если порядок операций БД (не совпадает с порядком операций диспетчера объектов) не важен, вы можете оставить реализацию JPA решать, когда выполнять сброс (например, при фиксации транзакции).

person Andrei I    schedule 10.02.2014
comment
Итак, для сеттеров мне нужен сброс, но мне не нужно начинать/завершать транзакцию? Но зачем смывать? Когда я читаю здесь и там, кажется, что сброс очищает кеш sql-команд (выполняет все операции немедленно), но почему бы не позволить JPA-Implementation решать, когда выполнять? - person dermoritz; 10.02.2014
comment
так что код в порядке, если не вызывается em.detach()? не глючный код: MyEntity entity = em.find(MyEntity.class, 1L); entity.setField (Новое значение); - person dermoritz; 10.02.2014
comment
Ну конечно; естественно. Это обычная ситуация. flush будет вызываться автоматически при фиксации транзакции :) - person Andrei I; 10.02.2014
comment
в моем случае сеттер работал без транзакции и без отсоединения - зачем мне здесь транзакция? - person dermoritz; 10.02.2014
comment
Вероятно, это сработало, потому что транзакция была автоматически запущена и зафиксирована для вас (например, в методах Spring @Transactional или EJB). Если это ваш случай, то это все объясняет и, конечно, вам не нужно открывать никаких сделок. Был ли ваш блок сохраняемости JTA или ресурс локальным? - person Andrei I; 10.02.2014
comment
Я использую обычный управляемый приложением jpa (локальный ресурс) в простом модульном тесте. И все сеттеры работают нормально и данные обновляются в бд без транзакций. Коллега сказал, что нужны транзакции, но я вспомнил из бывшего проекта, что сеттеры работают напрямую - и мы спросили здесь. - person dermoritz; 11.02.2014
comment
Из моего опыта: хотя спецификация JPA требует транзакцию и говорит, что TransactionRequiredException должно быть выброшено, если транзакция не привязана к сеансу (для упомянутых операций), в случае локального менеджера сущностей ресурса никакое исключение не выдается (например, это был Hibernate в контексте JAVA EE). В любом случае, не могли бы вы опубликовать немного своего кода? Также очень рекомендуется работать с транзакциями во всех тех случаях, когда вы меняете данные. Также попробуйте отключить режим автоматической фиксации вашего поставщика постоянства (ElipseLink в вашем случае), чтобы обеспечить выполнение транзакций. - person Andrei I; 11.02.2014
comment
Также ознакомьтесь с этой статьей о поведении, когда не установлены явные границы транзакций: community.jboss.org /wiki/ (ElipseLink должен вести себя аналогично) - person Andrei I; 11.02.2014