Spring Transaction совершает транзакции там, где не должен
В "applicationContext-base.xml" я добавляю ниже:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
>
.....
<!-- transaction support-->
<!-- PlatformTransactionMnager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- enable transaction annotation support -->
<tx:annotation-driven transaction-manager="txManager" />
и я хочу настроить транзакцию для функции в "контроллере"
@Controller
@RequestMapping("/ywdata")
public class YwController extends BaseController{
....
@Transactional(timeout=1)
private void submitNewSXSQ(Map map, HttpServletRequest request, HttpServletResponse response) throws Exception {
...//STEP1 :do some db insert and update STEP1
if(true)
throw new Exception("test transaction ");
...//STEP2: do another db insert and update
и я ожидал, что операция d b никогда не должна выполняться, так как перед возвращением я выкидываю исключение. но на самом деле нет.
2 ответа
Решение
Есть несколько проблем с вашим кодом:
@Transactional
на частные методы не работают@Transactional
на@Controller
аннотированные классы обычно не работают- Откат не выполняется для проверенных исключений
Последний вопрос легко понять. Позвольте мне объяснить первые две проблемы. АОП весной работает так:
- перед инициализацией контекста приложения Spring ищет компоненты, которые требуют перехвата метода
- для каждого из этих bean-компонентов зарегистрирован специальный прокси-компонент... прокси - это либо реализация динамического интерфейса (JDK-прокси), либо динамический подкласс (CGLIB-прокси) вашего целевого компонента
- прокси заменяет определение вашего bean-компонента... оригинальное определение переименовывается и помечается как неподходящее для автоматической проводки (но оно все еще присутствует в контексте приложения)
- методы в прокси очень глупы - все, что они делают, это логику перехвата (то есть, вызывая некоторый аспект до / после / вокруг выполнения) и вызывая исходный прокси-метод целевого компонента.
Почему частные методы являются проблемой:
- с прокси JDK (по умолчанию):
@Transactional
не будет работать, если у вас есть@Transactional
на неинтерфейсном методе (на прокси присутствуют только интерфейсные методы)
- с прокси CGLIB:
@@Transactional
не будет работать, если у вас есть@Transactional
на приватный или финальный метод (только динамические подклассы могут быть переопределены только не приватными и не финальными методами)
И почему контроллеры являются проблемой:
- Спринга
RequestMappingHandlerMapping
(bean отвечает за отображение запросов к вашему@Controllers
) просит контекст приложения получить все компоненты с@Controller
аннотирование- это может вернуть ваш исходный класс, а не прокси (я думаю, что в Spring JIRA была ошибка для этого, так что это может быть уже исправлено)
- в случае прокси JDK, вам нужно добавить аннотацию к интерфейсу (чтобы прокси был аннотирован)... это означает, что вам нужно будет определить интерфейсы для ваших контроллеров
Что делать:
- Я предлагаю вам перевести обработку транзакций на уровень обслуживания
- Если вы хотите, чтобы ваша транзакция охватывала весь запрос, вы можете черпать вдохновение из
OpenSessionInViewFilter
, - Также я рекомендую вам установить точку останова в вашем коде, проверить трассировку стека и найти прокси AOP.
- Если вы все еще хотите вручную обрабатывать транзакции в некоторой случайной части кода, вы можете использовать
TransactionTemplate
вспомогательный класс.
Из документации Spring это поведение по умолчанию: транзакции помечаются для отката только для непроверенных исключений.
Смотрите раздел 10.5.3 документа