2013-11-29 3 views
3

Недавно я столкнулся с интересной проблемой. Я использую в проекте JPA + Hibernate + EJB. Проблема заключается в сохранении и удалении объектов в одной транзакции. Используемая таблица базы данных имеет уникальное ограничение, определенное на двух столбцах.Порядок операций EntityManager

Что я делаю, это удаление сущности, призывающую

entityManager.remove(); 

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

entityManager.persist(); 

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

Очевидно, что я могу назвать

entityManager.flush() 

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

Я думал, что порядок операций такой же, как и в транзакции. Из моего примера получается, что это не так.

Есть ли способ решить проблему без промывки или совершения транзакции после удаления?

спасибо.

ответ

4

Очевидно, что я могу назвать entityManager.flush()

На самом деле вы должны назвать его.

Однако в этом случае данные сохраняются в базе данных до завершения всей транзакции .

Это неверно: данные синхронизируются с БД, но транзакция по-прежнему не выполняется, за исключением того, что вы выполняете ее вручную и имеете контроль над БД. Если вы не настроили что-либо в EJB, а единица персистентности - JTA (см. this question with comments), транзакция будет совершена только после возвращения методов из уровня EJB.

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

Нет, спецификация JPA не является обязательной для реализации. Вот почему есть операция flush().

Есть ли способ решить проблему без промывки или совершения транзакции после удаления?

Да, как я уже говорил, используется flush(). Также убедитесь, что вы используете механизм транзакционной базы данных (например, MyIsam в MySql не поддерживает транзакции).

+2

Я использую JTA, и я использую базу данных транзакций (Oracle), поэтому все должно быть хорошо. Блестящее объяснение Андрея. Я ошибся в вопросе о совершении транзакции. Теперь понятно. Я думаю, что вопрос и ответ будут полезны и для других людей. Спасибо. – Damian

0

Я была такая же проблема, и я решил ее так:
EntityManager.getTransaction().begin();
EntityManager.remove();
EntityManager.persist();
EntityManager.getTransaction().commit();
В случае каких-либо проблем Sperate в удалить и сохраняются операции в двух различных операций

+0

Однако мне нужно выполнить обе операции в одной транзакции. – Damian

2

Решение, предложенное Ossama Nasser, не рекомендуется, так как использование разных транзакций делает невозможным отмену отката до исходного состояния, если некоторые вещи терпят неудачу во втором или следующем транзакции ионов.

Решение entityManager.flush() является правильным решением.

+0

Это не следует добавлять как новый ответ, а как комментарий к ответу, на который вы ссылаетесь. –

+0

Да, но у меня еще нет репутации, чтобы сделать это ... –

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