记一次事务报错问题 Transaction synchronization is not active
問(wèn)題場(chǎng)景
在一次請(qǐng)求的返回結(jié)果中出現(xiàn)了這個(gè)錯(cuò)誤信息“Transaction synchronization is not active”,意思是“事務(wù)同步器沒(méi)有激活”,看著不像是業(yè)務(wù)代碼里返回的提示,猜測(cè)是spring事務(wù)框架報(bào)出來(lái)的異常沒(méi)有被捕獲而報(bào)的錯(cuò),在代碼里一通搜索之后確實(shí)沒(méi)發(fā)現(xiàn)這個(gè)提示信息,那是什么原因引起了這個(gè)異常呢?Google之。
出現(xiàn)原因
Google一番之后,發(fā)現(xiàn)了這篇文章Spring的TransactionEventListener,文中提到了可能出現(xiàn)這個(gè)錯(cuò)誤信息的一種情況:
@EventListener public void afterRegisterSendMail(MessageEvent event) {// Spring 4.2 之前TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {internalSendMailNotification(event);}}); }上面的代碼將在事務(wù)提交后執(zhí)行.如果在非事務(wù)context中將拋出java.lang.IllegalStateException: Transaction synchronization is not active
于是去代碼中搜索TransactionSynchronizationManager,果然在當(dāng)前請(qǐng)求鏈路中的一個(gè)service里發(fā)現(xiàn)了類似的代碼:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {logger.info("afterCommit_car_move_to_otherwarehouse_carIds:{}", new Gson().toJson(form.getCarIdList()));for (Long wmsCarId : form.getCarIdList()) {MovedCarMessage movedCarMessage = new MovedCarMessage();movedCarMessage.setOldCarId(wmsCarId);Message message = MessageBuilder.of(movedCarMessage).topic(carMoveToOtherWarehouseMessageTopic).build();messageProducer.syncSend(message);}}});想必是執(zhí)行這段代碼的時(shí)候報(bào)的異常,但是上面那篇文章說(shuō)了引起這個(gè)異常的原因是“在非事務(wù)context中注冊(cè)同步器”,難道當(dāng)前事務(wù)沒(méi)有開(kāi)啟?我們的業(yè)務(wù)代碼一般都是使用spring的注解@Transactional來(lái)開(kāi)啟事務(wù),那么去看一下開(kāi)啟事務(wù)的代碼片段。
根本原因
我在調(diào)用TransactionSynchronizationManager.registerSynchronization()的方法體上找到了@Transactional注解,方法代碼如下,省略具體實(shí)現(xiàn):
@Transactional@Overridepublic BizResult departingCar(CarDepartingForm form, User user) {···}這就奇怪了,明明方法上已經(jīng)添加@Transactional注解開(kāi)啟事務(wù),為什么事務(wù)開(kāi)啟失敗,帶著這個(gè)疑問(wèn)再次求助了Google,發(fā)現(xiàn)了這篇博客spring的service類調(diào)用自己方法事務(wù)無(wú)效,作者也遇到了事務(wù)無(wú)效的問(wèn)題,其中總結(jié)了事務(wù)有效性相關(guān)的幾點(diǎn)重要信息:
1.在需要事務(wù)管理的地方加@Transactional 注解。@Transactional 注解可以被應(yīng)用于接口定義和接口方法、類定義和類的 public 方法上。
2.@Transactional 注解只能應(yīng)用到 public 可見(jiàn)度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會(huì)報(bào)錯(cuò), 但是這個(gè)被注解的方法將不會(huì)展示已配置的事務(wù)設(shè)置。
3.注意僅僅 @Transactional 注解的出現(xiàn)不足于開(kāi)啟事務(wù)行為,它僅僅 是一種元數(shù)據(jù)。必須在配置文件中使用配置元素,才真正開(kāi)啟了事務(wù)行為。(spring配置文件中,開(kāi)啟聲明式事務(wù))
4.通過(guò) 元素的 “proxy-target-class” 屬性值來(lái)控制是基于接口的還是基于類的代理被創(chuàng)建。如果 “proxy-target-class” 屬值被設(shè)置為 “true”,那么基于類的代理將起作用(這時(shí)需要CGLIB庫(kù)cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 屬值被設(shè)置為 “false” 或者這個(gè)屬性被省略,那么標(biāo)準(zhǔn)的JDK基于接口的代理將起作用。
5.Spring團(tuán)隊(duì)建議在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實(shí)現(xiàn)的任何接口上。在接口上使用 @Transactional 注解,只能當(dāng)你設(shè)置了基于接口的代理時(shí)它才生效。因?yàn)樽⒔馐?不能繼承 的,這就意味著如果正在使用基于類的代理時(shí),那么事務(wù)的設(shè)置將不能被基于類的代理所識(shí)別,而且對(duì)象也將不會(huì)被事務(wù)代理所包裝。
6.@Transactional的事務(wù)開(kāi)啟 ,或者是基于接口的 或者是基于類的代理被創(chuàng)建。所以在同一個(gè)類中一個(gè)無(wú)事務(wù)的方法調(diào)用另一個(gè)有事務(wù)的方法,事務(wù)是不會(huì)起作用的。
特別注意第6點(diǎn):同一個(gè)類中一個(gè)無(wú)事務(wù)的方法調(diào)用另一個(gè)有事務(wù)的方法,事務(wù)是不會(huì)起作用的。這一點(diǎn)引起了我的注意,可能我的加了注解@Transactional的departingCar方法也是被類里另一個(gè)沒(méi)有開(kāi)啟事務(wù)的方法調(diào)用,如果真的是這樣,所有一切都解釋的通了。
果然,departingCar方法被一個(gè)沒(méi)加事務(wù)的接口方法調(diào)用,從而整個(gè)方法都沒(méi)有事務(wù)效果:
//此接口方法未加事務(wù) @Overridepublic BizResult departingCarFlowFinish(CarDepartingForm form, User user) {···//在此調(diào)用事務(wù)方法BizResult departResult = departingCar(form, user);···}解決方案
知道了引起問(wèn)題的原因,解決方法也比較簡(jiǎn)單,有好幾種方法都可以解決這個(gè)問(wèn)題,本文列出其中兩種:
1.比較方便、暴力的一種方法就是直接在最外層接口方法中添加事務(wù)注解,也就是給本文中的departingCarFlowFinish方法加上注解即可。
2.也可以通過(guò)代理類調(diào)用departingCar方法,代理類中包含了事務(wù)邏輯,這樣也能實(shí)現(xiàn)事務(wù)功能。
轉(zhuǎn)載于:https://www.cnblogs.com/muxuanchan/p/11357953.html
總結(jié)
以上是生活随笔為你收集整理的记一次事务报错问题 Transaction synchronization is not active的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 创业的21条军规
- 下一篇: 多次执行echarts时出现 there