隔离级别
数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事务的并发操作中可能会出现脏读,不可重复读,幻读。
A事务 | B事务 | |
1 | A事务开启 | |
2 | B事务开启 | |
3 | A事务读取数据为1000,并且使用了update,把数据改为2000 | |
4 | B事务读取数据为2000 | |
5 | A事务提交 |
A事务 | B事务 | |
1 | A事务开启 | |
2 | B事务开启 | |
3 | A事务读取数据为1000,并且使用了update,把数据改为2000 | |
4 | A事务提交 | |
5 | B事务读取的数据为2000 |
网上这样描述:InnoDB在每行记录后面保存两个隐藏的列来,分别保存了这个行的创建时间和行的删除时间。这里存储的并不是实际的时间值,而是系统版本号,当数据被修改时,版本号加1。在读取事务开始时,系统会给当前事务一个版本号,事务会读取版本号<=当前版本号的数据。此时如果其他写事务修改了这条数据,那么这条数据的版本号就会加1,从而比当前读事务的版本号高,读事务自然而然就读不到更新后的数据了。
这里把版本号抽象为列属性version,便于理解。
id | data | version |
1 | 1000 | 01 |
表1
id | data | version |
1 | 2000 | 02 |
表2
A事务 | B事务 | |
1 | A事务开启,读取id为1且版本号为01的数据 | |
2 | B事务开启,读取id为1且版本号为01的数据 | |
3 | A事务update了data的数据,data等于2000,这条数据的版本号变为2 | |
4 | A事务提交 | |
5 | B事务所获取的该数据的版本号仍为1,B事务再次读取数据,结果仍为1000 |
脏读(事务级别设置为读未提交引起)
A和B两个事务去读取一条数据,A事务对该条数据进行了修改,B事务恰好读取到了A修改后的数据,但是A事务并没有提交,而是在接下来的过程中发生了回滚或者再次修改了这条数据,但是B事务并不知道,那么可以说B事务读取的数据为脏数据,B事务进行了脏读。
A事务 | B事务 | |
1 | A事务开启 | |
2 | B事务开启 | |
3 | A事务读取数据为1000,并且update数据为2000 | |
4 | B事务读取数据为2000 | |
5 | A事务发生了回滚,数据重新变成1000 | |
6 | B事务执行update操作,在2000的基础上加1000 | |
7 | 提交事务,结果为3000(脏数据)。实际数据应为2000 |
不可重复读(数据级别设置为读提交或更低级别引起)
A和B两个事务去读一条数据,B读取数据后A事务对该条数据进行了修改并提交,当B事务再次读取这条数据时,发现数据变了。这里就回答了上面提到的问题,把数据隔离级别设置为读提交就有可能在并发时出现不可重读的错误。
A事务 | B事务 | |
1 | B事务开启 | |
2 | A事务开启 | |
3 | B事务读取数据为1000 | |
4 | A事务执行了update,数据变为2000 | |
5 | A事务进行了提交 | |
B事务再次读取数据,数据为2000 | ||
注 | B事务对同一条数据前后读取了两次,然而结果却不同,这就是不可重复读 |
幻读(前后两次读取的数据总量不一致)
A事务 | B事务 | |
1 | A事务开启 | |
2 | 读取的数据条数为100 | |
3 | B事务开启 | |
4 | 新增能加了50条数据 | |
5 | 提交事务 | |
6 | A事务再次读取数据条数,发现为150条 | |
注 | A前后两次读取的数据条数不相同,此为幻读 |
不可重复读和幻读的区别
不可重复度是针对update操作,幻读是针对insert操作delete操作
事务隔离级别与脏读、幻读和不可重读的关系(√:会出现 ×:不会出现)
脏读 | 不可重复读 | 幻读 | |
读未提交 | √ | √ | √ |
读提交 | × | √ | √ |
可重复度 | × | × | √ |
序列化 | × | × | × |
原文:https://www.cnblogs.com/gaonac/p/11809238.html