2013-05-22 5 views
1

Использование Hibernate JPA и Spring @Transactional (с реализацией Atomikos JTA) У меня есть следующие лица, в моей системе:Spring JPA @Transactional Atomic

  • Заказать
  • строки заказа (содержит ссылку на заказ)
  • Заказчик

в методе класса Service addOrder с аннотацией @Transactional Я хочу, чтобы выполнить следующие шаги, в одном TRANSACTI on (это один атомный функциональный блок).

  1. Упорство ордена
  2. упорствуем OrderLines
  3. PERSIST Заказчик

На шаге 1 (сохраняющиеся орден) Я хочу JPA откатить на любом Exception.

На шаге 2 (сохранение позиций заказа) Я хочу игнорировать любые ошибки во время сохранения строки заказа. Поэтому, если у меня есть 10 строк порядка и 1 не удается по какой-либо причине (например, ограничение ограничения), я хочу продолжить работу с остальными.

На шаге 3 В случае любого Exception я хочу JPA откатить всю сделку, так и все, что было сделано на шаге 1 и 2.

Проблемы я столкнулся, до сих пор:

  • JPA отмечает транзакцию как «откат только» в случае Exception. Так что все, после того, как (и раньше) это откат, но я хочу, чтобы игнорировать Exception на шаге 2.
  • JPA знает о нарушении ограничений после flush() или commit() называется, которая, как правило, после того, как метод @Transactional закончен , Мне нужно было бы знать это в моем методе.
  • Пробовал разбивать каждый шаг в отдельном методе @Transactional, но так как им нужно использовать тот же Transaction, это не изменит предыдущие две проблемы.

Каков наилучший подход для этого?

Update

Должен ли я поставить все проверки в Java и вручную проверить, если запись уже существует, например?

ответ

1

Поместите вторую часть в блок try-catch. Например: тело метода, вероятно, будет выглядеть так.

save(order); 
flush(); 
for(Orderline line : orderlines) { 
    try { 
     orderlineService.save(line); 
     flush(); 
    } catch(RuntimeException rte) { 
     continue; 
    } 
} 
save(customer); 
+0

@Bhasit В этом случае я столкнулся с проблемой 2, упомянутой выше. Нарушение ограничения (сущность уже существует, например) может быть замечена только при совершении фиксации. Эта фиксация выполняется только в конце основной службы, поскольку это конец транзакции. –

+0

Вы хотите игнорировать нарушения контртерминала? Кроме того, какой менеджер транзакций вы используете? –

+0

В принципе, я хотел бы быть abled, чтобы игнорировать любое (Runtime) исключение, вызванное сохранением позиции заказа. Мы используем Atomicos. –

0

На шаге 2 (сохраняющегося в OrderLines) Я хочу, чтобы игнорировать любые ошибки во отношении существующих в качестве OrderLine.Так что, если у меня есть 10 строк порядка и 1 не удается по какой-либо причине (например, нарушение ограничения), я хочу, чтобы продолжался с остальными.

@Transactional по умолчанию ТРЕБУЕТСЯ. Каждый метод invocationg соединяет текущую транзакцию, делая все 3 операции атомарными.

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

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 
public void persistMyOrderLine(OrderLine o) throws Exception{} 

из-за неудачи, сохраняющиеся в OrderLine не должны влиять на другой, новая транзакция должна быть создана для каждого. Таким образом, прерывание транзакции-OrderLineA не влияет на TransactionB-OrderlineB.

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

Возможно, вам стоит рассмотреть эти потребности.

+0

с этой настройкой. Я получаю проблемы с шагом 3. Если с этим что-то пойдет не так, мне придется откат. Но поскольку строки заказов уже совершены в отдельной транзакции (из-за Propagation.REQUIRES_NEW), я не могу отменить эти строки заказа. И кроме того, в «Заказе» есть ссылка на заказ, который находится в незафиксированной транзакции. Я считаю, что нарушу ограничение ссылочной целостности. –

0

Нужен ли заказ? Может ли Шаг 2 стать этапом 3?

Если это так, поместите шаги 1 & 3 в одну транзакцию и каждый отдельный persist Orderline в свою собственную транзакцию, которая будет запущена впоследствии. Конечно, это не будет работать, если вам нужно откатить, если все OrderLines не сохраняются ...

Другой подход может заключаться в создании неуправляемого EntityManager для работы с Orderline лиц; запускать транзакции, исключение catch и управлять commit/rollback самостоятельно для них.

В идеале вы использовали бы вложенную транзакцию, которая JPA/JTA doesn't directly support. У вас может быть какое-то подобие, сделав транзакцию фиксации/отката внешней транзакции зависимой от успеха/неудачи внутренних транзакций - или проигнорируйте (в вашем случае) внутреннюю транзакцию.

«Атомность» имеет тенденцию быть относительным зверем на практике - в значительной степени зависит от силы вашей «изоляции транзакций» и выбрана «уровень блокировки» (оптимистичный или пессимистический с вариациями).

Мои первоначальные соображения по этому поводу состоят в том, что если вы подошли к этому как проблема синхронизации потоков и сохранили некоторую согласованность в порядке вложенности («внешний», всегда имеющий дело с X, а «внутренний» всегда имеет дело с «Y»,) - вы должны быть в порядке, потому что порядковый номер , в котором применяются изменения, останется неизменным.

+0

Ваш первый подход будет работать в этой конкретной ситуации. Но я мог бы представить, что у меня есть другой набор объектов, которые я хочу сохранить и игнорировать исключения для него. Тогда у меня будет такая же проблема. Что касается другого подхода, то это будет совсем другая транзакция, так что это сломает мою атомарность, не так ли? –

+0

см. Обновление для моих мыслей –

+0

Если вы игнорируете исключения некоторых объектов, все равно транзакция? Это приведет к сбою C ACID. Интересно, что решение будет работать с точками сохранения, но да, JPA не очень хорошо справляется с этим. – Luciano

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