[英]@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"/>
implements
ControllerInterface
,其中方法簽名已被提取(源 -> 重構 -> Eclipse 中的提取接口)。<aop:aspectj-autoproxy proxy-target-class="true" />
以啟用“CGLIB 代理”。但這些都沒有幫助。 數據仍未從控制器回滾。
類似主題: 1 . 沒有提供解決方案。
我們找到的唯一解決方案是實現一系列新的@Component
類(我們稱之為"Delegates"
,但這是我們的術語),它們“鏡像”控制器並包含從控制器調用的業務邏輯。 所以例如
ReviewController
Each Method -> 調用ReviewDelegate
Each Method,這就是每個方法的業務邏輯所在的位置。
所有這些“委托”類都將觀察事務( @Component
),因為它們是@Component
,這對於控制器是不可能的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.