MySQL事务隔离级别
2021-07-27 本文已影响0人
晚歌歌
事务ACID特性
- 原子性(Atomicity):事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做——undo log
- 一致性(Consistency):事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态
- 隔离性(Isolation):一个事务的执行不能对其它事务形成干扰——锁
- 持久性(Durability):也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的——redo log
事务并发问题
- 脏读:一个事务读取到另一个事务还未提交的数据
- 不可重复读:同一个事务在整个事务过程中对同一笔数据进行读取,每次读取结果都不同
- 幻读:同样一笔查询在整个事务过程中多次执行后,查询所得的结果集是不一样的
不可重复读和幻读区别:不可重复读关注读取的数据本身对比,幻读关注读取数据的条数对比
事务隔离级别
在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别,不同的隔离级别对事务的处理不同。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
读已提交(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是(INNODB不会) |
串行化(serializable) | 否 | 否 | 否 |
MySQL的默认隔离级别是可重复读,但互联网项目中一般用读已提交
采用可重复读历史原因:
主从复制是基于binlog复制的,binlog有以下三种格式:
- statement:记录的是修改SQL语句
- row:记录的是每行实际数据的变更
- mixed:statement和row模式的混合
MySQL 5.7.7 之前,binlog 的默认格式都是 STATEMENT,在 5.7.7 及更高版本中,binlog_format 的默认值才是 ROW
MySQL在5.1.5这个版本以前,binlog只支持STATEMENT这种格式,而这种格式在读已提交这个隔离级别下主从复制是BUG的,可能导致主从数据不一致,解决方法:
- 隔离级别设置为可重复读,引入间隙锁
- 将binglog的格式修改为row格式,基于行的复制
由于历史原因MySQL选择了第一种方法
案例:读已提交级别
![](https://img.haomeiwen.com/i8100269/c15f81efc154bcb6.png)
- 主库的事务提交顺序是先插入后删除,但删除在内存中先执行并不会影响之前的插入
- 而从库也是按照事务提交顺序执行也是先插入后删除,重做后就会删除刚插入的记录
- 此时主库表中就存在一条记录,而从库没有记录
INNODB可重复读解决幻读
INNODB可重复读采用 Next-key 锁机制,解决幻读
- 记录锁:行锁
- 间隙锁:锁住索引之间的空隙,但是不包括记录本身
- Next-Key :记录锁+间隙锁