事务这个概念在MySQL是innodb特有的,事务的隔离级别一共有四种级别:读未提交、读已提交、可重复读和串行读。

  1. 读未提交:这一状态是四种隔离中执行最快的,但同样也是问题最多的。读未提交的意思是“当前事务可以读到同时期其它事务还没有提交的数据”,在该隔离级别下,如果事务A对blance表执行了update user set blance = 1000 where id = 1;(update前该记录blance = 0)此时事务还未提交,同时事务B执行了select blance from user where id = 1;,此时事务B会查到id=1的用户余额是1000,然后事务A因为一些原因执行失败,触发了undo log或者redo log的rollback发生回滚,然后事务B又来查id=1用户的blance,发现余额变成了0,也就发生了脏读的情况。此外,不可重复读、幻读等这些问题也会在该隔离级别下发生。

  2. 读已提交:这一状态下事务只能读到其它事务已经提交的数据,改隔离级别下效率不如读未提交,但可解决脏读的问题。还是刚才的例子事务A尝试修改余额为1000,然后事务B来读余额,但由于事务A未提交,所以事务B读到的blance还是事务A提交前的0,如果后面事务A失败触发回滚,事务B再来读的时候也是0,因此没有脏读的问题。读已提交是通过mvcc机制实现的,事务B在读的时候会生成一个read view,这个read view会去要读的这条记录的undo log版本链上找满足条件的第一个版本的数据返回。但无法解决不可重复读和幻读的问题。

  3. 可重复读:该隔离级别下,同一个事务的多个读操作会共用一个read view,从而解决不可重复读的问题。不可重复读的意思是,一个事务在不同的时间进行多次读取(中途有事务提交),读取到的数据值不一样。通过共用一个read view,使得读时访问到的都是同一个undo log版本链,从而保证了数据的一致性。SQL标准下说该隔离级别下无法解决幻读,但实际在MySQL中通过快照读读或当前读配合锁机制可以消除幻读:比如使用间隙锁锁定一定范围内的数据(间隙锁不锁定当前数据行),让这个范围内的数据无法在该事务结束前发生变更;或者使用行级锁➕间隙锁的组合next-key-locks锁定数据行和其相邻的间隙,保证该范围内在该事务未提交前不会发生变更。(关于快照读和当前读,其实就是时间换空间和空间换时间的关系,快照读通过记录快照的方式换取了非阻塞下的读一致性,但需要空间记录快照;当前读通过锁定记录实现读一致性,但其它事务需要排队等待锁释放,占用空间小但会阻塞)

  4. 串行读:四种隔离级别中隔离度最好的,也是效率最低的(低的还不少)。它的做法是通过InnoDB中的锁机制,让事务A在操作记录时将记录或表锁定,其它事务既无法读取也无法修改,只能等A事务释放锁后才能进行后续操作,也是这个原因,串行读彻底解决了上述所有问题(除了效率)。幻读的意思是当事务A读取表中的数据后(比如用了count(1)统计满足条件的记录),事务B在事务A还没结束的时候像表中插入了一条记录并提交(也可以是修改某条记录使其满足或不满足条件),然后事务A因为业务需要又执行了一次count(1),此时发现两次count(1)结果并不一致,就出现了幻读问题(这里的count函数只是举个例子,指的是两次统计得出的记录数量不一致)。

弹幕,最重要的是火力DA☆ZE!