Проблема распространения Spring Transaction - PullRequest
8 голосов
/ 26 августа 2010

Я использую управление транзакциями в Spring и Hibernate. Моя ситуация выглядит следующим образом:
У меня есть боб A , который теряет силу транзакции и он вызывает bean B , который определяется транзакцией, включающей атрибут PROPAGATION_REQUIRED

B в этом случае не открывает новую транзакцию, а использует ожидающую транзакцию (в журналах указано: «Участие в существующей транзакции»). Однако в случае, если метод в B сгенерирует исключение runtimeException, на обратном пути к A он испачкает транзакцию и заставит ее пометить для отката, даже если внешний метод A перехватит исключение и не выброси это. Я думаю, что это неправильное поведение, в этом случае я хочу, чтобы A управлял транзакцией, а B ни в коем случае не должен прерывать транзакцию.
Есть ли способ определить B для открытия транзакции, если транзакция не определена, но НИЧЕГО, если она уже находится внутри существующей транзакции, и пусть верхний уровень принимает решение о принятии или откате?

См. Больше отзывов об этой проблеме в теме в сообществе Spring здесь .

Ответы [ 5 ]

5 голосов
/ 07 ноября 2012

При настройке диспетчера транзакций Spring вы можете установить свойство с именем « globalRollbackOnParticipationFailure ». Если установлено значение false, исключение, возникающее в методе, который участвует в существующей транзакции, не помечает переход для отката. Транзакция помечается для отката только в том случае, если она исключена из метода, запустившего транзакцию.

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
    <property name="globalRollbackOnParticipationFailure" value="false" />
</bean>

См. JavaDoc для получения дополнительной информации.

5 голосов
/ 25 февраля 2011

Похоже, Propagation.NESTED - это то, что может вам помочь:

  • Если B завершится неудачно, транзакция, начатая с A (и продолженная с B), будет правильно откатиться до точки сохранения до вызова B, не касаясь A.
  • Когда фиксируется B, освобождается только точка сохранения, больше ничего не выдается в БД. Это означает, что изменения, сделанные B, «объединены» в транзакцию A.
  • После завершения B, в любом вышеупомянутом случае A может решить, будет ли продолжена погода и зафиксировать (это будет реальная фиксация в БД, которая будет включать все изменения на A и B [если она зафиксирована ]) или для отката (который откатит транзакцию до состояния, когда она была создана, и все изменения будут отменены на A + B).
3 голосов
/ 26 августа 2010

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

(Возможно, вам придется определить пользовательскую аннотацию, поскольку вы не можете ни переопределить атрибут @Transactional, ни расширить перечисление Propagation.)

Вот несколько указателей:

Также вам следует почитать книгу AspectJ в действии , даже если вы просто хотите использовать Spring AOP, поскольку она дает очень хороший обзор.

Хорошей отправной точкой является загрузка исходников jar-аспекта jar , посмотрите, что они там делают, и предоставьте свое собственное расширение либо org.springframework.transaction.aspectj.AbstractTransactionAspect, либо org.springframework.transaction.aspectj.AnnotationTransactionAspect

Подводя итог: я уверен, что это можно сделать, но это займет много работы. Хотя API-интерфейс Spring Transaction довольно хорош. Может быть, вы должны научиться жить с его ограничениями. Если нет: начать взлом (см. Выше)

0 голосов
/ 30 августа 2010

Одним из решений является предоставление ДВУХ определений bean-компонентов в вашем context.xml.

  • Один с PROPAGATION_REQUIRED, который вы будете использовать, когда хотите, чтобы бин сам был транзакционным

  • Второй с PROPAGATION_SUPPORTS, который вы будете использовать при вызове компонента из существующей транзакции (на самом деле, он может даже быть нетранзакционным).

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

0 голосов
/ 27 августа 2010

Может быть, использование аннотации @Transactional способом, показанным ниже, решит вашу проблему?@Transactional (распространение = Propagation.REQUIRED, noRollbackFor = RuntimeException.class)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...