簡體   English   中英

控制器方法上的@Transactional 不會回滾事務,但服務方法上會

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

免責聲明:是的,我知道@Transactional應該只放在服務方法上,理想情況下。

我正在支持一個舊的和設計糟糕的應用程序,其中所有業務邏輯都在 Controller 方法中混亂,並且這些方法不是事務性的,因此錯誤不會觸發回滾並且數據已損壞。

我們的團隊需要一個快速修復來為這個遺留應用程序啟用錯誤回滾,因此決定將@Transactional放在控制器方法上(而不是重構應用程序,這將是一項重大工作)。

但是,當我在 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 方法不接受或尊重它呢?

應用上下文:

<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 代理”。 現在控制器implements ControllerInterface ,其中方法簽名已被提取(源 -> 重構 -> Eclipse 中的提取接口)。
  2. 添加<aop:aspectj-autoproxy proxy-target-class="true" />以啟用“CGLIB 代理”。

我從中獲得這些想法的相關主題: 1 , 2

但這些都沒有幫助。 數據仍未從控制器回滾。

類似主題: 1 . 沒有提供解決方案。

我們找到的唯一解決方案是實現一系列新的@Component類(我們稱之為"Delegates" ,但這是我們的術語),它們“鏡像”控制器並包含從控制器調用的業務邏輯。 所以例如

ReviewController Each Method -> 調用ReviewDelegate Each Method,這就是每個方法的業務邏輯所在的位置。

所有這些“委托”類都將觀察事務( @Component ),因為它們是@Component ,這對於控制器是不可能的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM