Transaction rolled back because it has been marked as rollback-only分析解决方法
1.
Transaction rolled back because it has been marked as rollback-only
事务已回滚,因为它被标记成了只回滚
<prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
query开头的方法readOnly,所以只能select,抛出异常,insert/update/delete操作必然回滚
2.
发现selectA调用selectB,如果selectB抛出Exception,selectA中捕获Exception但是并不继续向外抛出,最后会出现错误。
纠其原理其实很简单,在selectB返回的时候,transaction被设置为rollback-only了,但是selectA正常消化掉,没有继续向外抛。
那么selectA结束的时候,transaction会执commit操作,但是 transaction已经被设置为 rollback-only了。
所以会出现这个错误。
有的同学说了,那不是没得搞了,service不能抛出异常,或者不能拦截异常了?
其实不然,其实错误不在这里,而是select这种操作为什么要启动事务呢?
3.demo示例代码
1.applicationContext.xml配置事务
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- <tx:method name="sendIllegalMessage" read-only="false" rollback-for="Exception" propagation="REQUIRES_NEW" /> -->
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="load*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="add*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="batchAdd*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="save*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="insert*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="update*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="modify*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="delete*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="del*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="registe*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="approve*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="clear*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="set*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="reset*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="getUpdate*" read-only="false" rollback-for="Exception" propagation="REQUIRED" />
<tx:method name="updatedQuery*" read-only="false" rollback-for="Exception" propagation="REQUIRES_NEW" />
<!-- <tx:method name="*" read-only="true"/> -->
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* com.xxx.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.v30.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.v31.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.v33.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.v34.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.limitCoupon.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.v35.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.v36.service..*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.auth.*Service.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(* com.xxx.notify.*Service.*(..))" advice-ref="txAdvice"/>
</aop:config>
2.junit测试代码
@Test
public void testCancelTask2(){
try {
transService.updateTransCancel2();
} catch (Exception e) {
e.printStackTrace();
}
}
public void updateTransCancel2() {
int upCount = transMapper.updateTransCancelStat(520657512071l, 1, 0, 0,-1,-1,-1,-1,-1,-1);
try {
cancelTransSendSms.cancelTransSendSms2();
} catch (Exception e) {
e.printStackTrace();
}
logger.info("upCount="+upCount);
}
public void cancelTransSendSms2() throws Exception{
aotoCancel2();
}
private void aotoCancel2() {
txtMap=smsConverUtil.getMessage(smsParamsMap, "RenterNoAuthDeposite", "RenterNoAuthDeposite0000");
}
public Map<String,String> getMessage(Map<String,Object> smsParamsMap,String smsContentKey,String pushKey){
Map<String,String> map=new LinkedHashMap<String, String>();
String smsContent="";
String jpushContent="";
String smsMessage="";
String flag="";
logger.info("in rentNo->smsContentKey is {}",smsContentKey);
if(StringUtils.isNotBlank(smsContentKey)){
smsContent=getContent(smsParamsMap,smsContentKey);
smsMessage=smsMsgDescMap.get(smsContentKey);
}
if(StringUtils.isNotBlank(pushKey)){
jpushContent=getPushContentTemplate(pushKey,smsParamsMap);
flag=pushMsgFlagMap.get(pushKey);
}
map.put("smsContent",smsContent);
map.put("jpushContent",jpushContent);
map.put("smsMessage",smsMessage);
map.put("flag",flag);
return map;
}
private String getPushContentTemplate(String contentKey,Map<String,Object> contentParamMap){
try {
String templateContent = operationService.getTemplateMsgByAppTypeAndCode(AppTypeConstant.JPUSH, contentKey);
if(StringUtils.isEmpty(templateContent)){
return null;
}
return replaceTemplateContent(templateContent,contentParamMap);
} catch (Exception e) {
logger.error("推送消息获取消息内容报错!",e);
}
return null;
}
public String getTemplateMsgByAppTypeAndCode(String appType, String textCode) {
try {
return operationTextCache.getUpdateOperateTextMsgByAppTypeAndTextCode(appType, textCode);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String tgetTemplateMsgByAppTypeAndCode(String appType, String textCode) {
return operationTextCache.tfindOperateTextMsgByAppTypeAndTextCode(appType, textCode);
}
public String findOperateTextMsgByAppTypeAndTextCode(String appType,
String textCode) {
OperationText operationText = this.findOperationTextByAppTypeAndTextCode(appType, textCode);
if (operationText==null) {
throw new IllegalArgumentException("appType:"+appType+","+"textCode:"+textCode+",不存在文本模板消息");
}else {
return operationText.getTextMsg();
}
} public String getUpdateOperateTextMsgByAppTypeAndTextCode(String appType,
String textCode) {
OperationText operationText = this.findOperationTextByAppTypeAndTextCode(appType, textCode);
if (operationText==null) {
throw new IllegalArgumentException("appType:"+appType+","+"textCode:"+textCode+",不存在文本模板消息");
}else {
return operationText.getTextMsg();
}
} public String tfindOperateTextMsgByAppTypeAndTextCode(String appType,
String textCode) {
OperationText operationText = this.findOperationTextByAppTypeAndTextCode(appType, textCode);
if (operationText==null) {
throw new IllegalArgumentException("appType:"+appType+","+"textCode:"+textCode+",不存在文本模板消息");
}else {
return operationText.getTextMsg();
}
}
4.汇总(A调用B)
4.1 A无事务,B无事务(将find,get改成tfind,tget方法名) A不回滚,不报以上错误。
4.2 A无事务,B get,find只读事务,但是不抛出throw new IllegalArgumentException("appType:"+appType+","+"textCode:"+textCode+",不存在文本模板消息"); A不回滚,不报以上错误。
4.3 A update事务,B get,find只读事务且抛出异常 (间隔捕获) A回滚,报以上错误。
4.4 A无事务,B get,find只读事务且抛出异常 (间隔捕获) A回滚,报以上错误。
4.5 A update事务,B update事务且抛出异常 (间隔捕获) A回滚,报以上错误。
4.6 A update事务,B update事务且抛出异常且try..catch..B A不回滚,不报以上错误。
4.6 A无事务,B update事务且抛出异常且try..catch..B A不回滚,不报以上错误。
简单而言之:
方法1有try,方法2无try,方法3 find或get throws A回滚,报以上错误。 捕获的异常有间隔有问题。
方法1有try,方法2有try,方法3 find或get throws A不回滚,不报以上错误。 在抛出异常的上一级方法捕获没有问题。
基于以上的情况说明:类1方法1无事务,类2方法2有事务get/find无捕获,类3方法3无事务 --->报rollback-only错误。
基于以上的情况说明:类1方法1无事务,类2方法2有事务get/find有捕获,类3方法3无事务 --->不报rollback-only错误。 上文说的间隔try
类1方法1无事务,类2方法2有事务get/find有无捕获,类3方法3有事务 --->报rollback-only错误。 被spring标记了rollback位,这就是为什么要REQUIRES_NEW事务了。
类1方法1无事务,类2方法2有事务updatedQuery新建事务有捕获,类3方法3有事务 --->不报rollback-only错误。
类1方法1无事务,类2方法2有事务updatedQuery新建事务无捕获,类3方法3有事务 --->报rollback-only错误。
Transaction rolled back because it has been marked as rollback-only分析解决方法的更多相关文章
- 【Spring】21、用spring目标对象处理Transaction rolled back because it has been marked as rollback-only
在使用spring做事务管理时,很多人都会遇到这样一段异常: org.springframework.transaction.UnexpectedRollbackException: Transact ...
- “Transaction rolled back because it has been marked as rollback-only”
spring的声明事务提供了强大功能,让我们把业务关注和非业务关注的东西又分离开了.好东西的使用,总是需要有代价的.使用声明事务的时候,一 个不小心经常会碰到“Transaction rolled b ...
- Transaction rolled back because it has been marked as rollback-only
出现这种错误的原因 1.接口A 调用了接口B 2.接口B报异常了,没有在B里面进行try catch捕获 3.接口A对 接口B进行了try catch捕获 因为接口B报异常 会把当前事物A接口的事物( ...
- 【springcloud】Transaction rolled back because it has been marked as rollback-only
问题: 一个ajax请求,发生系统错误,错误内容:Transaction rolled back because it has been marked as rollback-only 原因是调用的s ...
- [转]Spring事务嵌套引发的血案---Transaction rolled back because it has been marked as rollback-only
原文地址:https://blog.csdn.net/f641385712/article/details/80445912 1.概述 想必大家一想到事务,就想到ACID,或者也会想到CAP.但笔者今 ...
- Transaction rolled back because it has been marked as rollback-only 原因 和解决方案
产生原因 , 1 serviceA 调用 serviceB 然后 B 抛出异常 ,B 所在的 事物 回滚,B 把当前可写 事物标记成 只读事物 , 2 如果 A 和B 是在 同一个事物环境,并且 ...
- Spring事务嵌套引发的问题--Transaction rolled back because it has been marked as rollback-only
转载https://blog.csdn.net/f641385712/article/details/80445912 读了两边才找到问题
- 记一次org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only异常
@Transactional(rollbackFor = Exception.class) @Overridepublic DubboResult<Boolean> productAddO ...
- spring事务(Transaction )报 marked as rollback-only异常的原因及解决方法
很多朋友在使用spring+hibernate或mybatis等框架时经常遇到报Transaction rolled back because it has been marked as rollba ...
随机推荐
- BZOJ4077 : [Wf2014]Messenger
二分答案,让$A$推迟出发$mid$的时间. 对于每个相邻的时间区间,两个点都是做匀速直线运动. 以$A$为参照物,那么$A$不动,$B$作匀速直线运动. 若线段$B$到$A$的距离不超过$mid$, ...
- 关于在ViewPager的子页面中不能跳转的问题
关于在ViewPager的子页面中不能跳转的问题 什么是ViewPager? 相信很多人使用过微信,其实微信的四个子页面:微信.通讯录.发现.我以及下面的引导空间就是ViewPager. 出现的问题: ...
- Spring+Quartz实现定时任务的配置方法(转)
1.Scheduler的配置 <bean id="myScheduler" class="org.springframework.scheduling.quartz ...
- 部署前准备--使用Mysql之Django Debug Toolbar安装以及配置
python -c "import django ;print(django.__path__);" 查看python的全局配置 vi /usr/local/lib/python3 ...
- 小甲鱼Python第八讲课后习题
0. 下面的循环会打印多少次"I Love FishC"?
- 【小y设计】二维码条形码打印编辑器
条码打印,价格标签打印,需要对打印进行排版,于是设计了一个简单的编辑器 支持条码二维码打印进行编辑排版,支持文字.图片.条码.二维码.直线,能自由拖拉,删除,并可保存为模版. 界面如下 (下载Demo ...
- Map network drive遇到报错“The network folder specified is currently mapped using a different user name and password”,怎么办?
--------------------------- Windows --------------------------- The network folder specified is curr ...
- jpa-规范
看图
- org.springframework.web.method.HandlerMethod 与 org.springframework.messaging.handler.HandlerMethod 转换失败
Springmvc hander.getclassclass org.springframework.web.method.HandlerMethod HandlerMethod.classclass ...
- python-写入excel(xlswriter)
一.安装xlrd模块: 1.mac下打开终端输入命令: pip install XlsxWriter 2.验证安装是否成功: 在mac终端输入 python 进入python环境 然后输入 imp ...