记一次 Spring 事务配置踩坑记

问题描述:(SpringBoot + MyBatisPlus)

业务逻辑伪代码如下。理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条件会不满足,会查询不到数据。结果事与愿违,后一次的查询,居然查到了数据。

void saveXxx(){
 xxService.getXxx(); // 查到一条数据 data1
 xxService.insert(); // 插入一条数据 t1
 xxService.getXxx(); // 查到一条数据 data1
}

分析过程:

抛弃业务逻辑,在一个新的 service 中写了一个最简单的测试,查询 --> 插入 --> 查询。为了保证两者具有可比性,sql 都从原 Mapper 中拷贝过去。但是依然重现不了问题。神奇的是出现了如下的情况:

@Transactional
void testMyBatis(){
 yyService.getYyy(); // 查到一条数据 data1
 yyService.insert(); // 插入一条数据 t1
 yyService.getYyy(); // 查不到数据
 xxService.getXxx(); // 查到一条数据 data1
}

理论上,yyService.getYyy() 与 xxService.getXxx() 应该都查不到数据才对,结果只有 xxService.getXxx() 能查到。

开始怀疑事务的问题,是不是 xxService.getXxx() 新开启了一个事务去查询,只有这样,xxService.getXxx() 的查询条件才不受当前事务插入的数据所影响。

检查项目中的事务配置,除了配置了注解式事务外,还有如下的声明式事务配置:

@Bean
public TransactionInterceptor txAdvice() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setReadOnly(true);
readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
requiredTx.setTimeout(TX_METHOD_TIMEOUT);
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("add*", requiredTx);
txMap.put("save*", requiredTx);
txMap.put("insert*", requiredTx);
txMap.put("update*", requiredTx);
txMap.put("delete*", requiredTx);
txMap.put("get*", readOnlyTx);
txMap.put("query*", readOnlyTx);
source.setNameMap( txMap );
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;
}

就是这一行配置搞的鬼:readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED ); get*开头的方法都加了只读事务,而只读事务是以非事务方式运行,如果当前存在事务,则把当前事务挂起。

这样就解释了为什么 xxService.getXxx() 方法能够查到数据了,它是在当前事务之外查询的数据。

解决办法:

将 readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED ); 去掉。

附:还是使用注解式事务吧 ^_^

记一次 Spring 事务配置踩坑记的更多相关文章

  1. spring事务配置的坑

    基于 <tx> 命名空间的声明式事务管理 前面两种声明式事务配置方式奠定了 Spring 声明式事务管理的基石.在此基础上,Spring 2.x 引入了 <tx> 命名空间,结 ...

  2. Gitlab Jenkins WebHook 持续集成配置踩坑记

    Jenkins相关介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 目的 配置Gitla ...

  3. react中的路由配置踩坑记

    react 路由配置中,如果根路由(/)匹配一个组件,另一个路由(/list)在进行匹配的时候也会匹配到根路由(/),即在 /list 页面展示的时候 / 页面总是展示在上方. 此时如果想进行严格匹配 ...

  4. vscode 配置踩坑记

    vscode-easy-less 遇到问题最好的解决方式是看官网文档,切记!!! 在web开发当中,经常会写less然后编译成css,当然在VS Code当中也有这样的插件(EasyLess), 但是 ...

  5. Spring @Transactional踩坑记

    @Transactional踩坑记 总述 ​ Spring在1.2引入@Transactional注解, 该注解的引入使得我们可以简单地通过在方法或者类上添加@Transactional注解,实现事务 ...

  6. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  7. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  8. Spark踩坑记——共享变量

    [TOC] 前言 Spark踩坑记--初试 Spark踩坑记--数据库(Hbase+Mysql) Spark踩坑记--Spark Streaming+kafka应用及调优 在前面总结的几篇spark踩 ...

  9. Spark踩坑记——从RDD看集群调度

    [TOC] 前言 在Spark的使用中,性能的调优配置过程中,查阅了很多资料,之前自己总结过两篇小博文Spark踩坑记--初试和Spark踩坑记--数据库(Hbase+Mysql),第一篇概况的归纳了 ...

随机推荐

  1. 集合(2)—Collection之List的使用方法

    声明集合变量 List list = new ArrayList(); 或者 : public LIst list: public 构造函数(){ this.list = new ArrayList( ...

  2. 用Jersey构建RESTful服务1--HelloWorld

    一.环境1.Eclipse Juno R22. Tomcat 73. Jersey 2.7  下载地址( https://jersey.java.net/download.html) 二.流程1.Ec ...

  3. c++ try catch 问题

    以前都是用try{} catch(…){}来捕获C++中一些意想不到的异常, 今天看了Winhack的帖子才知道,这种方法在VC中其实是靠不住的.例如下面的代码: 以前都是用try{} catch(… ...

  4. C#编程(七十五)----------C#使用指针

    原文链接: http://blog.csdn.net/shanyongxu/article/details/47321441 在C#中使用指针的语法 如果想在C#中使用指针,首先对项目进行过配置: 看 ...

  5. Windows XP Ghost系统安装

    一.双击Ghost系统安装工具,进入Ghost界面 二.依次单击[Local]-[Partition]-[From Image],可以简单记作1-2-3. 弹出对话框,选择.GHO文件,比如XP.GH ...

  6. iOS开发-装饰模式

    装饰模式是指在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.通过创建一个包装对象,也就是装饰来包裹真实的对象.装饰模式中的装饰对象和真实对象有相同的接口.这样客户端对象就能以和真实对象 ...

  7. SpringBoot(八):系统错误统一拦截器

    在日常 web 开发中发生了异常,往往需要通过一个统一的 异常处理,来保证客户端能够收到友好的提示.本文将会介绍 Spring Boot 中的 全局统一异常处理. Springboot的全局异常查是通 ...

  8. aglio报错解决

    Cannot write or read cache for themes (ENOENT on cache folder) aglio -i ./api.md -o api.html >> ...

  9. MySql之删除操作

    一:删除特定行 DELETE FROM 表名 WHERE 条件: 二:删除所有行 TRUNCATE TABLE 表名; //删除重建一张表

  10. ROS actionlib学习(三)

    下面这个例子将展示用actionlib来计算随机变量的均值和标准差.首先在action文件中定义goal.result和feedback的数据类型,其中goal为样本容量,result为均值和标准差, ...