2013-12-04 4 views
2

У меня есть метод Spring MVC Controller, который помечен как «Транзакционный», который выполняет несколько служебных вызовов, которые также помечены как «Транзакционные», но они рассматриваются как независимые транзакции и выполняются отдельно вместо все по одной транзакции, как я желаю.Сделка не работает правильно - Spring/MyBatis

Основываясь на выходе отладки, появляется, что Spring создает транзакции только при достижении служебных вызовов. Я увижу вывод «Создание новой транзакции с именем ...» только для них, но не для метода контроллера, который их вызывает.

Есть ли что-то очевидное, что мне не хватает?

Пример кода (сокращенно) ниже, контроллер:

@Controller 
public class BlahBlah etc... 

@Autowired 
SomeService someService; 

@Transactional 
@RequestMapping(value="windows/submit", method=RequestMethod.POST) 
@ResponseBody 
public String submit (@RequestBody SomeObject blah) throws Exception { 

    someService.doInsert(blah); 

    if (true) throw Exception("blah"); 

    ... other stuff 
} 

код услуги:

public interface SomeService { 

@Transactional 
public void doInsert (SomeObject blah); 
} 

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

Таким образом, в результате я получаю принудительное исключение и проверю таблицу, вставка зафиксировала вместо отката назад, как я хочу.

Так что же я сделал не так?

Почему Spring игнорирует тег Transactional на контроллере?


проводки соответствующую часть моего контекста в соответствии с просьбой комментатора:

web.xml:

<context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value> 
      classpath:spring.xml 
      classpath:spring-security.xml 
      classpath:spring-datasource.xml 
     </param-value> 
    </context-param> 

    <servlet> 
     <servlet-name>springmvc</servlet-name> 
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
     <init-param> 
      <param-name>contextConfigLocation</param-name> 
      <param-value>classpath:spring-mvc.xml</param-value> 
     </init-param> 
     <load-on-startup>1</load-on-startup> 
    </servlet> 

    <servlet-mapping> 
     <servlet-name>springmvc</servlet-name> 
     <url-pattern>*.html</url-pattern> 
    </servlet-mapping> 

Sping-mvc.xml:

<context:annotation-config/> 
    <context:component-scan base-package="com.blah"/> 
    <mvc:annotation-driven/> 

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" p:order="1" /> 

... non-relevent stuff 

<mvc:interceptors> 
    <mvc:interceptor> 
     <mvc:mapping path="/**"/> 
     <bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor"> 
      <property name="cacheSeconds" value="0"/> 
      <property name="useExpiresHeader" value="true"/> 
      <property name="useCacheControlHeader" value="true"/> 
      <property name="useCacheControlNoStore" value="true"/> 
     </bean> 
    </mvc:interceptor> 
    <mvc:interceptor> 
     <mvc:mapping path="/**"/> 
     <bean id="httpInterceptor" class="com.blah.BlahInterceptor" /> 
    </mvc:interceptor> 
    </mvc:interceptors> 

    <mvc:view-controller path="/" view-name="blah"/> 

    <context:component-scan base-package="com.blah"/> 

Хм, вот заинтересованные и непреднамеренные - у меня есть дублирование компонентов. Может ли это быть причиной этого?

+0

Пожалуйста, разместите свой контекст. Вероятно, вы не правильно проверили классы контроллера. –

+0

OK good suugestion, я отредактирую свое сообщение и добавлю его в конец – Trant

ответ

2

Я думаю, что Spring игнорирует аннотацию @Transactional здесь, потому что она создает прокси для транзакции, но диспетчер не вызывает контроллер через прокси.

Там интересная заметка в the Spring MVC documentation, 17.3.2, о аннотировании контроллеров, она не описывает вашу проблемы, но точно показывает, что есть проблемы с этим подходом:

распространенной ошибкой при работе с аннотированным классы контроллера происходит при применении функциональных возможностей, требующих создания прокси для объекта контроллера (например, методы @Transactional). Обычно вы будете ввести интерфейс для контроллера, чтобы использовать JDK dynamic прокси. Чтобы сделать эту работу, вы должны перенести аннотации @RequestMapping , а также любые другие аннотации типа и уровня метода (например, @ModelAttribute, @InitBinder) на интерфейс, а также механизм отображения может только «видеть» интерфейс выставленный прокси. В качестве альтернативы вы можете активировать proxy-target-class = "true" в конфигурации для функций, применяемых к контроллеру (в нашем сценарии транзакций ). Это означает, что следует использовать прокси-классы подкласса на основе CGLIB вместо прокси-серверов JDK на основе интерфейса. Для получения дополнительной информации о различных механизмах проксирования см. Раздел 9.6 «Механизмы проксирования».

Я думаю, вам было бы лучше создать еще одну услугу, чтобы обернуть существующие и аннотировать это.

+0

Спасибо Nathan, я пытаюсь реализовать ваше предложение о добавлении другой услуги для обертывания вызовов, но столкнувшись с проблемой, когда MyBatis думает, что мой сервис является классом сопоставления - задал еще один вопрос: http://stackoverflow.com/questions/20406045/why-is-mybatis-mapper-scanner-picking-up-wrong-class – Trant

+0

Нет, не работает. Теперь у меня есть отдельный класс, который реализует интерфейс, и этот класс имеет метод, который обертывает все вызовы службы и имеет тэг @Transactional, но он все же создает транзакцию для независимых вызовов службы, а не основного метода обертки! – Trant

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