【问题标题】:@Transactional on Controller Method does not roll back transactions, but on Service Methods does控制器方法上的@Transactional 不会回滚事务,但服务方法上会
【发布时间】:2020-03-02 17:01:10
【问题描述】:

免责声明:是的,我知道 @Transactional 应该只放在 Service 方法上,理想情况下。

我正在支持一个陈旧且设计不佳的应用程序,其中所有业务逻辑都在 Controller 方法中杂乱无章,并且这些方法不是事务性的,因此错误不会触发回滚并且数据已损坏。

我们的团队需要快速修复以启用此旧应用程序的错误回滚,因此决定将 @Transactional 放在 Controller 方法上(而不是重构应用程序,这将是一项重大工作)。

但是,当我在 Controller 方法上尝试以下操作时,它并没有回滚我的异常:

@Controller
public class ReviewDetailsController extends BaseController{

@RequestMapping(value={"/testException"}, method = RequestMethod.POST)
@Transactional(readOnly = false, rollbackFor = Exception.class)
public void testException(@RequestParam(required = true) String planId) throws Exception {  

    // Simulate some simple DB change: we'll change a Date to a dummy value, 03:33:33
    Plans plan = planService.findById(new Integer(planId));
    PlanWorkflow pw = processService.getLatestWorkflow(plan);
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
    Date d = sdf.parse("12/06/2019 03:33:33");
    pw.setCreatedDate(d);

    // Save it
    processService.savePlanWorkflow(pw);

    // Exception test
    throw new Exception("EXCEPTION TEST");          

}

另一方面,当将完全相同的逻辑放入示例服务类方法中时,它确实成功回滚。

Controller现在调用Service方法,Service方法有@Transactional

@RequestMapping(value={"/testException"}, method = RequestMethod.POST)
@Transactional(readOnly = false, rollbackFor = Exception.class)
public void testException(@RequestParam(required = true) String planId) throws Exception { 

    // Call a Service method with the exact same logic from the Controller
    processService.testException(planId);   
}

服务

@Component
public class ProcessServiceImpl implements ProcessService {

    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void testException(@RequestParam(required = true) String planId) throws Exception {  

        // Simulate some simple DB change: we'll change a Date to a dummy value, 03:33:33
        Plans plan = planService.findById(new Integer(planId));
        PlanWorkflow pw = processService.getLatestWorkflow(plan);
        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        Date d = sdf.parse("12/06/2019 03:33:33");
        pw.setCreatedDate(d);

        // Save it
        processService.savePlanWorkflow(pw);

        // Exception test
        throw new Exception("EXCEPTION TEST");          

    }

理论上,每个人都说我应该能够将@Transactional 附加到 Controller 方法(尽管不建议这样做——但我仍然应该能够做到)。那么为什么 Controller 方法不接受它或尊重它呢?

applicationContext:

<context:component-scan base-package="mypackage.myapp">
</context:component-scan>

<jpa:repositories base-package="mypackage.myapp.dao"/>

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="/META-INF/persistence.xml"/>
</bean>

<cache:annotation-driven/> 

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
      p:cache-manager-ref="ehcache"/>

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
      p:config-location="/WEB-INF/ehcache.xml"/>


我尝试过的事情:
  1. 使控制器实现一个接口,以启用“JDK 代理”。现在是控制器implementsControllerInterface,其中方法签名已被提取(Source -> Refactor -> Extract Interface in Eclipse)。
  2. 添加&lt;aop:aspectj-autoproxy proxy-target-class="true" /&gt; 以启用“CGLIB 代理”。

我从中获得这些想法的相关主题:12

但是这些都没有帮助。数据仍未从 Controller 中回滚。

类似线程:1。没有提供解决方案。

【问题讨论】:

  • 谢谢,这里是:&lt;spring.version&gt;4.3.12.RELEASE&lt;/spring.version&gt;
  • @Controller之后添加@Transactional注解
  • 没用....

标签: java spring spring-mvc spring-data-jpa


【解决方案1】:

我们找到的唯一解决方案是实现一系列新的@Component 类(我们称之为"Delegates",但这是我们的术语),它们“镜像”控制器并包含从控制器。所以例如

ReviewController Each Method -> 调用ReviewDelegate Each Method,这就是每个方法的业务逻辑所在。

所有这些“委托”类都将观察事务(带有回滚),因为它们是 @Component,而直接使用控制器是不可能的。

【讨论】:

    猜你喜欢
    • 2019-01-27
    • 2017-03-29
    • 2019-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    • 2019-03-04
    • 1970-01-01
    相关资源
    最近更新 更多