事务隔离级别引发的"血案"
事务引发的"血案"见的多了也麻木了,这回遇到个事务隔离级别的"案子",坑了我小半天的时间...也怪自己细节不牢..
敲着代码遇到这么一个怪事情:
class XXXService{
@Transactional
public void demo(){
//一堆业务逻辑
rpc.insertOne(); //dubbo调用远程服务插入一条数据
getOne(); //获取刚才插入的数据
}
}
其中getOne()的事务的传播属性是required, 因为dubbo是远程调用,所以实际上返回后插入的数据就已经commit了, 一个事务中commit的数据另一个事务中应该可以读取到...本来是这样的,但是呢getOne()方法中却读取不到新插入的数据..
倘使如果不是用dubbo远程调用插入数据的话, 我可能还不会误入歧途, 因为数据库是本地自己搭建的, 平时也没人改默认配置, 按照以往经验Mysql默认配置的情况上面的例子应该是可以读取到的. 所以我把关注点放到这个rpc调用上去了..浪费了很多时间..反正是折腾了很久, 各种推导测试事务传播,想来想去也应该没问题.后来干脆把事务去掉了,发现正常了,传播属性各种测试基本确定没有任何问题了,那么问题可以确定是在事务隔离性上..饶了一大圈这才刚刚走上正道....
SELECT @@session.tx_isolation;
通过命令查询了一下mysql数据库的隔离配置,发现是 Repeatable Read, 咦, 这个和记忆中的默认配置貌似对不上(这里实际上是我记混了,mysql默认配置的确是这个,Oracle才是Read committed)..赶紧查询一下线上的数据库配置果然不对应该是Read Committed
这下问题明了,由于代码中没有写明隔离级别,所以使用的是mysql配置的隔离级别,而mysql的隔离级别是可重复读,故产生了此次问题.
此次问题做一个小结:
产生原因:
查询数据库的时候会建立一个到数据库的连接, 熟称数据库session, 有事务的情况下, 这一次连接就处于一个事务中, rpc调用远程服务,由于不是本地方法,故无法加入本地事务中,所以可以算作是另一个事务,那么rpc所处的事务插入数据后事务就结束并提交了. 而getOne()方法所处的事务实际上并没有完成,还受到事务配置的约束,又由于没有配置事务的隔离属性,故采用的mysql的隔离配置Repeatable Read, 而这个可重复读的意思就是一个数据可以反复读取, 并且读取到的值不会发生变化, 这实际上就是说当建立此次事务的时候就不会再读取到新的值了.那么在事务中途rpc插入的数据也不在getOne()所处事务可以读取的范围内, 故读取不到. 但是如果隔离的属性是Read Committed的话,则可以读取到已经提交的数据, rpc服务虽然是中途插入的数据,但是由于新插入的数据已经提交了事务,故依然可以被getOne()方法读取到.
解决方法:
set global transaction isolation level read committed;
最简单的方法是直接变更mysql的隔离配置为read committed,这样就一切归位了.如果无法变更数据库隔离级别也依然有办法,由于隔离配置的生效级别是首先按照程序中配置的级别,其次再看数据库配置的,那么在程序中变更隔离级别也可以.
class XXXService{
@Transactional(isolation = Isolation.READ_COMMITTED)
public void demo(){
//一堆业务逻辑
rpc.insertOne(); //dubbo调用远程服务插入一条数据
getOne(); //获取刚才插入的数据
}
}
问题到此就结束了,但是这里有一个问题比较好奇,Reaptable Read是如何实现的呢,感觉像是开启事务后就对数据库进行了一个快照一样,但是想想又不可能真这样做,然后百度到了一个介绍mysql mvcc机制的文章.
简单来说就是实际上在每行数据最后有2列隐藏列,一列代表数据的创建版本,一列代表数据的删除版本,列中的值存放的是版本号,而这个版本号就是递增的且和某个事务唯一对应,这样只要查询创建版本小于当前版本,删除版本大于当前版本就可以了,换成白话就是查询在当前版本之前创建,当前版本之后删除的数据,这样就可以保证对于当前版本能查询到的数据的稳定不可变,而对于修改数据的操作,则是拆分为标记原来的数据为删除,并插入一条修改后的数据,这样就完美巧妙的保证修改数据读取的稳定性.
事务隔离级别引发的"血案"的更多相关文章
- 30分钟全面解析-SQL事务+隔离级别+阻塞+死锁
以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化. 本系列主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础] ...
- 事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理
1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单 ...
- Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现分布式事务管理
原创说明:本文为本人原创作品,绝非他处转载,转账请注明出处 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). ...
- Sqlserver事务隔离级别详解
sqlserver存储方式 页 sqlserver是以页的形式存储数据,每个数据页的大小为8KB,sqlserver会把空间分为多个页,sqlserver与数据交互单位最小的io操作就是页级 ...
- 事务,Oracle,MySQL及Spring事务隔离级别
一.什么是事务: 事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败. 二.事务特性(4种): 原子性 (atomicity):强调事务的不可分割:一致性 (consiste ...
- SQL Server 事务隔离级别
一.事务隔离级别控制着事务的如下表现: 读取数据时是否占用锁以及所请求的锁类型. 占用读取锁的时间. 引用其他事务修改的行的读操作是否: 在该行上的排他锁被释放之前阻塞其他事务. 检索在启动语句或事务 ...
- SQL Server中锁与事务隔离级别
SQL Server中的锁分为两类: 共享锁 排它锁 锁的兼容性:事务间锁的相互影响称为锁的兼容性. 锁模式 是否可以持有排它锁 是否可以持有共享锁 已持有排它锁 否 否 已持有共享锁 否 是 SQL ...
- 从事务隔离级别谈到Hibernate乐观锁,悲观锁
数据库的事务,是指作为单个逻辑工作单元执行的一系列操作. 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源.通过将一组相关操作组合为一个要么全部成功要么全部失败的单 ...
- 事务以及MySQL事务隔离级别+MySQL引擎的区别
1.事务的基本要素:ACID 1.原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有 ...
随机推荐
- PCA-主成分分析(Principal components analysis)
来自:刘建平 主成分分析(Principal components analysis,以下简称PCA)是最重要的降维方法之一. 1. PCA的思想 PCA顾名思义,就是找出数据里最主要的方面,用数据里 ...
- oracle listagg和wm_concat函数
对于将一列多值合并成一行问题,oracle提供了wmsys.wm_concat和listagg函数处理此问题,下面我们以emp表中数据为例,看看两函数的使用方法 假设我们需要统计每种job下面有哪些员 ...
- python 判断两个列表中相同和不同的元素
背景: 在做接口自动化时,通常会判断接口返回中的数据信息,与数据库中返回的数据信息是否一致,比如:将接口返回信息的用户姓名存放到一个列表中,将数据库返回的用户姓名存放到另一个列表中,这时需要判断两个列 ...
- redhat 配置yum源(配置163 yum repo)
一般安装好redhat后,不能注册的话,不能使用系统自带的yum源.但是我们可以自己配置yum源来解决这一问题.下面介绍下redhat配置163yum源. 1) 查看版本号和系统类别: cat /et ...
- [转]C++中const、volatile、mutable的用法
原文:https://blog.csdn.net/imJaron/article/details/79657642 const意思是“这个函数不修改对象内部状态”. 为了保证这一点,编译器也会主动替你 ...
- Codeforces 813E - Army Creation
813E - Army Creation 思路: 线段树+二分 先预处理每个点往后走k步的下标 线段树二叉树的每个节点用vector维护这些下标,给这些下标排个序 询问区间L,R,那么把下标小于等于R ...
- WebSocket前后台交互
其实对于前后台交互有很多种方法(只列举我知道的,嘻嘻): 1:from 表单: 使用场景——小信息量提交给后台 2:ajax(跨域的话用jsonp): 可以进行多量的前后台信心传递: 但实时性不高,不 ...
- github优秀前端项目分享(转)
http://microjs.com/# 该网站的资源都托管到了github,microjs.com是一个可以让你选择微型的js类库的网站,该网站里的js库都是压缩后不大于5KB的,非常实用 http ...
- Axure 第一次交互 实现跳转页面
- GenomicConsensus (quiver, arrow)使用方法 | 序列 consensus
https://github.com/PacificBiosciences/GenomicConsensus GenomicConsensus 是pacbio开发的,我个人非常不喜欢pacbio开发的 ...