MySQL事务总结
操作数据过程中可能出现的问题
- 第一类更新丢失:覆盖丢失。A事务修改,B事务修改,B事务提交,A事务提交。
- 第二类更新丢失:回滚丢失。A事务修改,B事务修改,B事务提交,A事务回滚。
- 脏读:读到了无效数据(已回滚的数据)。
- 不可重复读:在一个事务中,两次读到的同一行数据不一样。
- 幻读:在一个事务中,两次读到的多行数据行数不一样(有新增或删除)。
查看MySQL的默认配置
支持的存储引擎
show engines;
可以看到,只有InnoDB支持事务,也就是MySQL的默认存储引擎。
默认事务隔离级别
select @@global.tx_isolation;
当前会话的事务隔离级别
select @@tx_isolation;
默认autocommit
show variables like ‘autocommit’;
MySQL的所有操作都在一个事务内,默认采用“可重复读”隔离级别,默认开启autocommit,一个操作一个事务,事务执行完后自动提交。
为什么MySQL不会出现两类“更新丢失”问题
在InnoDB中,所有修改数据的操作(增删改)都要先获取排他锁(写锁),没有获取到排他锁的修改操作会放入wait queue中等待,直到获取锁或超时。获取了排他锁的事务只有在提交或回滚后才会释放锁。MySQL的事务回滚采用undo log完成,undo log记录了修改操作的逆过程,事务回滚只会回滚本事务的修改,不会影响其他事务已提交的修改。因此通过锁机制和回滚机制就保证了不会出现“更新丢失”问题,与事务的隔离级别无关。
简单总结四种隔离级别
为了兼顾数据一致性和并发能力,MySQL支持四种隔离级别,简述其实现原理,分别解决的问题,和存在的问题
读未提交
使用“排他写锁”实现。A事务可以读到B事务已修改但还未提交的数据,但A事务不能修改B事务未提交的数据。由于A事务读了B事务未提交的数据,所以B事务发生回滚时,A事务会出现脏读。此外,还会出现不可重复读和幻读。
读已提交
使用MVCC实现,每次查询都会生成新的ReadView,包含了当前正在运行的所有事务ID,然后查找版本链中最近已提交的结果。A事务不能读到B事务已修改但还未提交的数据,解决了脏读。没有解决不可重复读和幻读。
可重复读
使用MVCC实现,首次查询会生成一个ReadView,下次查询复用上次的ReadView,保证了两次查询结果一致。A事务过程中对相同记录的多次查询结果不变,解决了不可重复读。同时ReadView的机制也解决了读场景下的幻读,但没有解决写场景下的幻读。要解决写场景下的幻读,还需要配合InnoDB的间隙锁来解决。
序列化(串行化)
所有请求串行执行,彻底解决所有并发带来的问题,但严重影响性能。
参考文章
Mysql隔离级别层面是否解决了 第一类更新丢失和第二类更新丢失的问题
mysql 第二类更新丢失_myslq的更新丢失实例
面试官:谈谈你对Mysql的MVCC的理解
MySQL的可重复读级别能解决幻读吗
MVCC 原理