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 ответа

Решение

Есть несколько проблем с вашим кодом:

Последний вопрос легко понять. Позвольте мне объяснить первые две проблемы. АОП весной работает так:

  • перед инициализацией контекста приложения 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 документа

Другие вопросы по тегам