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分析解决方法的更多相关文章

  1. 【Spring】21、用spring目标对象处理Transaction rolled back because it has been marked as rollback-only

    在使用spring做事务管理时,很多人都会遇到这样一段异常: org.springframework.transaction.UnexpectedRollbackException: Transact ...

  2. “Transaction rolled back because it has been marked as rollback-only”

    spring的声明事务提供了强大功能,让我们把业务关注和非业务关注的东西又分离开了.好东西的使用,总是需要有代价的.使用声明事务的时候,一 个不小心经常会碰到“Transaction rolled b ...

  3. 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接口的事物( ...

  4. 【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 ...

  5. [转]Spring事务嵌套引发的血案---Transaction rolled back because it has been marked as rollback-only

    原文地址:https://blog.csdn.net/f641385712/article/details/80445912 1.概述 想必大家一想到事务,就想到ACID,或者也会想到CAP.但笔者今 ...

  6. Transaction rolled back because it has been marked as rollback-only 原因 和解决方案

    产生原因  , 1 serviceA 调用 serviceB 然后 B  抛出异常 ,B 所在的 事物 回滚,B 把当前可写 事物标记成 只读事物 , 2 如果 A 和B 是在 同一个事物环境,并且 ...

  7. Spring事务嵌套引发的问题--Transaction rolled back because it has been marked as rollback-only

    转载https://blog.csdn.net/f641385712/article/details/80445912 读了两边才找到问题

  8. 记一次org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only异常

    @Transactional(rollbackFor = Exception.class) @Overridepublic DubboResult<Boolean> productAddO ...

  9. spring事务(Transaction )报 marked as rollback-only异常的原因及解决方法

    很多朋友在使用spring+hibernate或mybatis等框架时经常遇到报Transaction rolled back because it has been marked as rollba ...

随机推荐

  1. HTTP断点续传

    一.概述   所谓断点续传,其实只是指下载,也就是要从文件已经下载的地方开始继续下载.在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了.一般断点下载时才用到Range和Conten ...

  2. visual studio 设计第一个WinForm小程序

    WinForm小程序之消息框 首先打开visual studio 软件,然后[文件]-[新建]-[项目]-[Visual C#]-[Windows],选择Windows窗体应用程序,根据自己的需要修改 ...

  3. 逻辑回归与神经网络还有Softmax regression的关系与区别

    本文讨论的关键词:Logistic Regression(逻辑回归).Neural Networks(神经网络) 之前在学习LR和NN的时候,一直对它们独立学习思考,就简单当做是机器学习中的两个不同的 ...

  4. ruby安装方法

    安装 Ruby Ruby官网下载:http://www.ruby-lang.org/en/downloads/(官网下载链接) 安装过程中,得注意,勾选上添加到环境变量 安装完成后,查看是否安装成功 ...

  5. 【总结】瞬时高并发(秒杀/活动)Redis方案

    1,Redis 丰富的数据结构(Data Structures) 字符串(String) Redis字符串能包含任意类型的数据 一个字符串类型的值最多能存储512M字节的内容 利用INCR命令簇(IN ...

  6. Javascript 字符串(一)常见函数使用

    一.js字符串示例1 <script type="text/javascript"> var strobject = new String('123abc123abc' ...

  7. C# Task WhenAny和WhenAll 以及TaskFactory 的ContinueWhenAny和ContinueWhenAll的实现

    个人感觉Task 的WaitAny和WhenAny以及TaskFactory 的ContinueWhenAny有相似的地方,而WaitAll和WhenAll以及TaskFactory 的Continu ...

  8. EChart配置

    EChart配置 https://www.jianshu.com/p/3cf80b96a65d

  9. Javascript : require.js 的使用(例子)

    demo 结构:     config.js require.config({ baseUrl: 'js/lib', paths: { 'jquery' : 'jquery-1.11.1.min', ...

  10. 云服务jdk 升级为 OpenJDK11

    由于oracle是个碧池,大家都懂,今年来,jdk版本更新的越来越频繁,所以目前商业版本需要收费了 每个企业都要考虑这样的问题,所以嘛,新项目试水肯定是要的,用openJDK11吧, https:// ...