交易无法正常工作 - Spring / MyBatis

时间:2013-12-04 20:38:44

标签: spring model-view-controller transactions

我有一个Spring MVC Controller方法,它被标记为“Transactional”,它使得几个服务调用也被标记为“Transactional”,但是它们被视为独立事务,并且根据我的需要单独提交而不是全部在一个事务下。

根据调试输出,看起来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);
}

我尝试从服务调用中删除Transactional标记,可能是我搞砸了,我告诉它为每个调用创建一个,但是在调试输出中没有创建事务。

结果是,一旦我得到强制异常并检查表,插件已经提交而不是像我想要的那样回滚。

那我做错了什么?

为什么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>

消费满-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"/> 

嗯,那是感兴趣和无意的 - 我有重复的组件扫描。这可能导致问题吗?

1 个答案:

答案 0 :(得分:2)

我认为Spring在这里忽略了@Transactional注释,因为它为事务创建了一个代理,但是调度程序没有通过代理调用控制器。

the Spring MVC documentation,17.3.2中有一个关于注释控制器的有趣注释,它没有描述你的确切问题,但表明这种方法存在问题:

  

使用带注释的控制器类时常见的陷阱   在应用需要创建代理的功能时发生   控制器对象(例如@Transactional方法)。通常你会   为控制器引入一个接口,以便使用JDK动态   代理。要使其工作,您必须移动@RequestMapping   注释,以及任何其他类型和方法级注释   (例如@ModelAttribute,@ InitBinder)到接口以及   映射机制只能“看到”代理公开的接口。   或者,您可以在中激活proxy-target-class =“true”   应用于控制器的功能的配置(在我们的   交易场景)。这样做表明   应该使用基于CGLIB的子类代理而不是   基于接口的JDK代理。有关各种代理的更多信息   机制见第9.6节“代理机制”。

我认为你最好创建另一个服务来包装现有服务并注释它。