事务隔离级别引发的"血案"
事务引发的"血案"见的多了也麻木了,这回遇到个事务隔离级别的"案子",坑了我小半天的时间...也怪自己细节不牢..
敲着代码遇到这么一个怪事情:
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): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有 ...
随机推荐
- Centos7 安装python3.7.2
下载python3.7.2源码 wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tgz 下载完后对压缩包解压缩 tar -xf Py ...
- 设计模式(六)Prototype Pattern 原型模式
通过new产生一个对象非常繁琐,可以使用原型模式 原型模式实现: ——Cloneable接口和clone方法 ——Prototype模式实现起来最困难的地方是实现内存的复制和操作,Java中提供了cl ...
- JavaSE习题 第九章 输入输出流
问答题 1.如果准备读取一个文件的内容,应该使用FileInputStream还是FileOutputStream? FileInputStream 2.FileInputStream流的read() ...
- maven项目依赖jar包报 java.lang.classnotfoundexception:Type com.xx.xx.xxx not present 的解决
今天在工作的时候遇到了这样一个奇葩的异常: java.lang.classnotfoundexception:Type com.ys.yahu.vo.file.MobileFileVo not pre ...
- python实战小程序之购物车
# Author:南邮吴亦凡 # 商品列表 product_list = [ ('Iphone',5800), # 逗号一定不可以省略! ('Mac',4800), ('smartphone',400 ...
- 数据结构(C语言版)-第5章 树和二叉树
5.1 树和二叉树的定义 树(Tree)是n(n≥0)个结点的有限集,它或为空树(n = 0):或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点:(2)除根结点以外的其余结点可分为m(m& ...
- 微信小程序分享
点击链接查看详情:(转发的路径的必须写正确) https://mp.weixin.qq.com/debug/wxadoc/dev/api/share.html
- php 中文字符串反转
/** * * 中文字符串倒序 * @param str $str * return str **/ function str_en_desc($str){ $len=mb_strlen($str); ...
- 虚拟机linux 如何挂在U盘,NTFS格式如何挂载
今天突发奇想,想挂载U盘到虚拟机的Centos 7 上,但是出了些问题,下边我就来说下linux挂在U盘的步骤 电脑插上U盘 win + R运行 services.msc 找到虚拟机的USB服务并运行 ...
- TeamViewer一直显示“未就绪,请检查您的连接”什么原因?
一.错误 错误:未就绪,请检查您的连接 二.问题原因 1.网络连接有问题 很多用户在点击启动TeamViewer的时候,在下方看到显示未连接状态.这种情况可能是软件自身问题,重启一下或重新下载安装包安 ...