赞
踩
事务的作用:
ACID:
(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)
多事务产生的问题:
脏读(dirty read)、
不可重复读(non-repeatable read)、
幻读(phantom read)
SQL的标准隔离级别:
读未提交(read uncommitted):一个事务还没提交时,它做的变更就能被别的事务看到。
读提交(read committed):一个事务提交之后,它做的变更才会被其他事务看到。
可重复读(repeatable read):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行化(serializable ):对于同一行记录读写都会加锁,所以同时只有一个事务可以访问此条数据。
读提交是没有间隙锁的。当Binlog为statement格式情况下可能会造成binlog的日志重放时数据不一致情况。须改成row模式。
因为Binlog记录为为按照提交顺序写入。此时sessionB,sessionC会首先写入然后才会写入A。
T5时刻查到了sessionC的新增记录,属于幻读情况。需要间隙锁去规避。
在此级别下,A事务启动时创建一个视图 read-view,之后当前事务A执行期间,即使有其他事务修改了数据,事务A看到的仍然在跟启动时一样。
示例
insert into t(id, k) values(1,1)
autocommit=1
![](https://img-blog.csdnimg.cn/20201128131238222.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTY3ODg1Mg==,size_16,color_FFFFFF,t_70![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321164932689.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTY3ODg1Mg==,size_16,color_FFFFFF,t_70
注意: begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才真正启动。
start transaction with consistent snapshot 这个命令马上启动一个事务
查询结果:
事务A得到K值为1,符合当前隔离级别所描述;
事务B得到K值为3,按照可重读规则,k值应该为2,有些不符合预想,针对于事务B最后的 查询得到值为3下面做详细的说明:
一:从时间线分析:
T1:事务A启动- 形成视图
T2:事务B启动- 形成视图
T3:事务B查询k值为1
T4:执行update k+1语句,执行完毕。此时数据库K落库值为2
T5:事务B执行update k+1语句,–此时出现一条更新规则: 更新数据为先读后写,这个读为只能读当前值,称为“当前读”。 所以更新语句前读到K值为当前落库值2,进行更新操作。(当此操作进行后,当前事务不提交,则id为1的这条记录其他事务更改会阻塞)
T5:事务B查询K值,在2中形成的视图中查询+自己修改的数据,得到K为3
T6:事务A查询K值,在1中形成的视图查询,得到K为1,事务A提交
T7:事务B提交,落库K值为3
二:从MVCC版本分析:
InnoDB 里面每个事务有一个唯一的事务 ID,为transaction id,事务开始向InnDB事务系统申请,严格按照申请顺序递增,每行数据会被多个事务更改,每次事务更新数据会生成新版本,并且把当前transaction id 赋值给这个新版本的事务 ID,记为row trx_id。 所以每行数据其实都有能有多个版本,每个版本有自己的row trx_id。
1:新增语句执行insert into t(id, k) values(1,1),假设事务ID为1, 此时定义当前版本row trx_id=1,
事务自动提交; 版本生效
2:事务C执行,将K值+1 变为2,事务C的ID定义为4,当前版本row trx_id=4,事务C提交,变更日志落库。版本生效
3: 事务B执行修改语句,因更新规则限制所以进行当前读 读到K值为2 ,row trx_id=4, 进行update将K值+1变为3,事务B的ID定义为3,row trx_id=3
4:事务B查询K值,(按照可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果/当前自己事务变更。但是之后,这个事务执行期间,其他事务的更新对它不可见),此时可以查到版本信息为3的数据,也就是自己事务更改的数据,及事务启动时的视图数据。 当前事务B未提交,所有针对于id=1的这条数据无法进行更新操作。
5:事务A查询K值,根据事务创建时的一致视图及自身事务ID进行查询,得到K值为1,事务A提交
6:事务B提交,版本生效,其他针对于ID=1的更新语句可以进行操作。
mysql的具体实现:
InnoDB为每个事务构造了一个活跃事务数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务 ID。并且保存了一个叫高水位的值。通过这个数组和高水位来组成一致性视图。
活跃事务数组:指的就是,启动了但还没提交。
低水位:活跃事务里面最小的事务ID的事务记为低水位。
高水位:当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。
一致性视图:通过这个活跃事务数组和高水位,组成了当前事务的一致性视图。
例子:
可重复度的级别下
事务15获查询id=1的数据行,当前数据行的数据版本可能存在多个。如何判断改查询的是哪个版本的数据行,就是通过 事务A启动时生成的一致性视图来区分。
根据定义进行判断是否能看到那个版本的数据行,在活跃事务数组内的数据行修改看不到,在高水位意以上的未来事务修改看不到,只能看到已提交和自己修改的版本。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。