@Transactional在Controller方法上不会回滚事务,但在Service Methods上却可以

Disclaimer: Yes, I know that @Transactional should only be put on Service methods, ideally.

我正在支持一个设计不佳的旧应用程序,在该应用程序中,所有业务逻辑都在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).

但是,当我在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");          

}

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

控制器现在调用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");          

    }

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). So why don't the Controller methods pick it up or honor it?

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"/>

如果这不起作用,是否还有其他快速方法可以为Controller方法提供事务性?