2010-03-05 5 views
2

Я пытаюсь использовать функцию управления декларативными транзакциями, предоставляемую Spring. Я установил конфигурацию Spring и bean-компоненты, как описано в справочной документации (включая AOP, пространства имен tx и использование тега <tx:annotation-driven />), и я использую аннотацию @Transactional для метода, который я хочу сделать транзакционным.проблема с использованием @Transactional аннотация

Вот как выглядит код:

public interface Worker { 
    public workOnEvents(List<Events> eventsForACustomer); 
} 

public class WorkerImpl { 
    @Transactional 
    public workOnEvents(List<Events> eventsForACustomer) { 
     for(Event event : eventsForACustomer) { 
      // get DAO's based on event types at runtime, 
      // so we will have different DAO's acting within this loop 
      DAOFactory.getDAO(event.getType()).persistEvent(event); 
     } 
    } 
} 

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

Итак, чтобы проверить откат, я взял список некоторых событий (e1, e2, e3), которые приведут к сбору DAO (d1, d2, d3), а затем я намеренно выкидываю исключение во время выполнения в метод persistEvent DAO d2. Тем не менее, результатом я получаю, что программа завершается без перехода к событию e3 в цикле, а не с обработкой созданного исключения. Кроме того, данные, сохраненные DAO d1, не откатываются назад.

Пожалуйста, дайте мне знать, что я могу делать неправильно здесь?

+0

Пожалуйста, добавьте журналы. – Padmarag

+0

Покажите фабрику Dao и произвольный класс DAO – Bozho

+0

Я отправлю код DAO, как только я составу один :) ... я хочу сказать, что это код, принадлежащий моей компании, и я опубликовал образец код здесь, который в основном моделирует то, что происходит. Что касается очистки в коде DAO, я проверил это, и это не тот случай. Могло ли это повлиять на настройки db config или Hibernate, установленные по умолчанию в моем приложении. Тем не менее, я вернусь с некоторым примером кода, который может как можно лучше смоделировать мою ситуацию. – abhinav

ответ

0

Вам необходимо добавить атрибут RollbackFor в аннотацию. Что-то вроде этого: @Transactional (распространение = Propagation.REQUIRED, rollbackFor = Throwable.class)

+0

распространение = распространение.REQUIRED - это значение по умолчанию, поэтому не обязательно. – Padmarag

+0

Разве это не по умолчанию? Я думаю, что в документации говорится, что исключения во время выполнения обрабатываются по умолчанию? – abhinav

+0

вы делаете флеш() где-то - я видел, что транзакции совершаются, если вызывается флеш ... – Arvind

0

только непроверенные исключения (то есть подклассы java.lang.RuntimeException) являются rollbacked по умолчанию.

Вам нужно добавить rollbackFor к @Transactional аннотации.

У вас также нет обработки исключений, поэтому e3 не будет выполнен.

+0

Как я уже упоминал, я выбрал исключение RuntimeException, так что это не должно быть проблемой. Тем не менее, если я поймаю исключение, как это будет распространяться на перекрестный уровень Spring, чтобы он мог откатиться? – abhinav

+0

Не могли бы вы также выслать код вашего DAO d2? – Padmarag

+0

Также добавьте код DAO d1. Там может быть фиксация/флеш. – Padmarag

0

Возможно, вы уже совершили предыдущую транзакцию, чтобы Java-часть больше не могла откатить ее.

Я думаю, либо:

  • ваш DB совершать все вставки/обновление
  • вашего DAO сделал это
1

Ваших ожиданий того, что должно произойти, не собираюсь, чтобы встретились с аннотациями подхода , Способ, которым он работает, - это аннотация, указывающая на метод как что-то, к которому Spring ссылается, а совет обертывает метод, поэтому материал может произойти до вызова метода, например, запуска новой транзакции и после завершения метода, например, совершения или откат транзакции. Когда вы описываете, что вы хотите вернуть e1 и e2 назад, необходимо выполнить e3, для чего требуется, чтобы код транзакции выполнялся посредине метода, поэтому использование рекомендаций для этого не будет работать.

Для контроля над транзакциями, которые вы хотите, вам необходимо обратиться к Spring's programmatic transaction API.

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

+0

Спасибо за ответ. Да, я добился того, чего хотел, используя API программных транзакций. Мое намерение таково: для клиента выбран определенный набор событий (согласно сегодняшним датам и бизнес-правилам), и их нужно обрабатывать (скажем, отправлять почту). Тем не менее, вся обработка событий, собранных для клиента, должна обрабатываться транзакционным образом, поэтому, даже если это не удается, любые изменения, внесенные в db для этого клиента, должны быть отброшены назад. Кроме того, ошибки, возникающие при обработке событий для клиента, не должны приводить к прекращению действия приложения. – abhinav

+0

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

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