简体   繁体   English

控制器方法上的@Transactional 不会回滚事务,但服务方法上会

[英]@Transactional on Controller Method does not roll back transactions, but on Service Methods does

Disclaimer: Yes, I know that @Transactional should only be put on Service methods, ideally.免责声明:是的,我知道@Transactional应该只放在服务方法上,理想情况下。

I am supporting an old and poorly-designed application where all the business logic is cluttered in Controller methods, and those methods aren't transactional, so errors don't trigger rollback and the data is corrupted.我正在支持一个旧的和设计糟糕的应用程序,其中所有业务逻辑都在 Controller 方法中混乱,并且这些方法不是事务性的,因此错误不会触发回滚并且数据已损坏。

Our team needs a quick fix to enable error rollback for this legacy application, so it was decided to put @Transactional on Controller methods (rather than refactor the application which would be a major effort).我们的团队需要一个快速修复来为这个遗留应用程序启用错误回滚,因此决定将@Transactional放在控制器方法上(而不是重构应用程序,这将是一项重大工作)。

However, when I tried the following on a Controller method, it didn't roll back my exception:但是,当我在 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");          

}

On the other hand, when put the exact same logic inside a sample Service class method, it did roll back successfully.另一方面,当将完全相同的逻辑放入示例服务类方法中时,它确实成功回滚。

Controller now calls Service method, the Service method has @Transactional 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);   
}

Service服务

@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");          

    }

In theory, everyone says I should be able to attach @Transactional to Controller methods (even though it's not recommended -- but I still should be able to do it).理论上,每个人都说我应该能够将@Transactional附加到 Controller 方法(即使不推荐这样做——但我仍然应该能够做到)。 So why don't the Controller methods pick it up or honor it?那么为什么 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"/>


Things I've tried: 我尝试过的事情:

  1. Make the Controller implement an Interface, to enable "JDK Proxy".使控制器实现一个接口,以启用“JDK 代理”。 Now the Controller implements ControllerInterface where the method signatures have been extracted (Source -> Refactor -> Extract Interface in Eclipse).现在控制器implements ControllerInterface ,其中方法签名已被提取(源 -> 重构 -> Eclipse 中的提取接口)。
  2. Add <aop:aspectj-autoproxy proxy-target-class="true" /> to enable "CGLIB Proxy".添加<aop:aspectj-autoproxy proxy-target-class="true" />以启用“CGLIB 代理”。

Related threads where I got these ideas from: 1 , 2 .我从中获得这些想法的相关主题: 1 , 2

But none of this helped.但这些都没有帮助。 Data still isn't getting rolled back from the Controller.数据仍未从控制器回滚。

Similar thread: 1 .类似主题: 1 . No solution offered.没有提供解决方案。

The only solution we found to this is to implement a new series of @Component classes (which we call "Delegates" , but that's our term) which "mirror" the Controllers and contain the business logic that gets called from the Controller.我们找到的唯一解决方案是实现一系列新的@Component类(我们称之为"Delegates" ,但这是我们的术语),它们“镜像”控制器并包含从控制器调用的业务逻辑。 So eg所以例如

ReviewController Each Method -> calls ReviewDelegate Each Method, and that's where the business logic resides for each method. ReviewController Each Method -> 调用ReviewDelegate Each Method,这就是每个方法的业务逻辑所在的位置。

All these "Delegate" classes will observe Transactions (with rollback) because they're @Component , which is impossible directly with a Controller.所有这些“委托”类都将观察事务( @Component ),因为它们是@Component ,这对于控制器是不可能的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring @Transactional注释不会回滚 - Spring @Transactional annotation does not roll back Spring在@Transactional方法中捕获JpaSystemException并回滚事务 - Spring Catch JpaSystemException in @Transactional Method and Roll Back Transaction @Transactional在方法级别不起作用 - @Transactional does not work on method level Spring TransactionalTemplate 不会在异常时回滚 - Spring TransactionalTemplate does not roll back on exception 如果调用在 Spring 中抛出 RuntimeException 的私有方法,@Transactional 方法是否应该回滚? - Should @Transactional method roll back in case of calling a private method which throws RuntimeException in Spring? 测试方法上的 @Transactional 注释是否在结束之前回滚注释方法中的每个事务? - Does @Transactional annotation on test methods rollback every transaction in the annotated method before it gets to the end? 为什么HibernateTransactionManager不会使DataSourceTransactionManage不回滚? - Why DataSourceTransactionManage does not roll back while HibernateTransactionManager does? Spring @Transactional 属性是否适用于私有方法? - Does Spring @Transactional attribute work on a private method? 挂起的@transactional 方法会阻塞资源吗? - Does suspended @transactional method block resource? @Controller类中的@Transactional方法不被视为事务性的 - @Transactional methods in @Controller class are not considred as transactional
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM