目录
一、事务隔离级别
二、脏读、幻读、不可重复读现象及解决办法
1、脏读
2、不可重复读现象
3、幻读现象
4、使用for update避免幻读
5、使用串行读避免幻读现象
三、快照读与当前读
1、理论
2、RR 下,快照建立时机 – 第一次 select 时
3、RR 下,快照建立时机 – 事务启动时
4、RR 下,快照建立时机 – 修改数据时
1.未提交读 - 读到其它事务未提交的数据(最新的版本)
错误现象:有脏读、不可重复读、幻读现象
2.提交读(RC) - 读到其它事务已提交的数据(最新已提交的版本)
错误现象:有不可重复读、幻读现象
使用场景:希望看到最新的有效值
3.可重复读(RR) - 在事务范围内,多次读能够保证一致性(快照建立时最新已提交版本)
错误现象:有幻读现象,可以用加锁避免
使用场景:事务内要求更强的一致性,但看到的未必是最新的有效值
4.串行读 - 在事务范围内,仅有读读可以并发,读写或写写会阻塞其它事务,用这种办法保证更强的一致性
错误现象:无
设置tx1隔离等级为未提交读,tx不用设置。tx2设置了账户1的值为2000,tx1查出得到2000,但是tx2事务还没有提交,如果出现事务回滚,那么tx1读出来的2000就是无效值,这就是脏读现象。
tx1设置提交读,这时候就没有脏读现象。tx1开启事务做了两次查询,两次查询中间tx2执行了一次更新的事务,但是对于tx1来讲,一次事务里两次查询结果不一致,到底以哪一次为准,或者说将结果用于运算,是用哪一次,这就造成了混乱,这就是不可重复读现象
tx1设置为可重复读,这个可以避免不可重复读现象。tx1开启事务做了两次查询,两次查询中间tx2执行了一次插入的事务,因为设置了可重复读,所以在第一次查询就会建立一个快照,别的事务对于数据库的增删改暂时不可见,所以tx1在插入账号3时出现了报错。
tx1在新增操作之前给一个不存在的记录加一个for update的锁,只允许自己来操作3号记录
tx1设置为串行读,在tx1执行读操作,会加一个共享读锁,其他事务可以读,但不能增删改
当前读,即读取最新提交的数据
select … for update
insert、update、delete,都会按最新提交的数据进行操作
快照读,读取某一个快照建立时(可以理解为某一时间点)的数据
快照读主要体现在 select 时,不同隔离级别下,select 的行为不同
在 Serializable 隔离级别下 - 普通 select 也变成当前读
在 RC 隔离级别下 - 每次 select 都会建立新的快照
在 RR 隔离级别下
①事务启动后,首次 select 会建立快照
②如果事务启动选择了 with consistent snapshot,事务启动时就建立快照
③基于旧数据的修改操作,会重新建立快照
tx1在开启事务第一次查询就会建立快照,第二个事务虽然修改了,但是因为是快照读,所以读出来是快照建立时状态
如果建立快照时间比较晚,他也会根据当前的状态建立
事务启动的时候也可以建立快照,修改事务启动语句,虽然update先执行,但是事务比update还早,所以读出来的数据不是更新后的数据。
修改数据是指基于旧的数据去修改,才会重新建立快照,tx2执行修改操作,是在原有旧值得基础上增加1000,所以此时会重新建立快照,tx1的增加也是原有的增加,又重新建立的快照。