共计 1758 个字符,预计需要花费 5 分钟才能阅读完成。
第一部分:概述
MySQL 遵循 SQL:1992 标准,提供 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ 和 SERIALIZABLE 四种事务隔离级别。InnoDB 默认使用的事务隔离级别是 REPEATABLE READ。
用户可以自己修改会话或全局级别的事务隔离级别,语法如下:
SET [GLOBAL | SESSION] TRANSACTION
transaction_characteristic [, transaction_characteristic] …
transaction_characteristic:
ISOLATION LEVEL level
| READ WRITE
| READ ONLY
level:
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
transaction_characteristic [, transaction_characteristic] …
transaction_characteristic:
ISOLATION LEVEL level
| READ WRITE
| READ ONLY
level:
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
你也可以在启动时添加 –transaction-isolation 启动项或者将其写入配置文件,来设置相应的全局事务隔离级别。
READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ 和 SERIALIZABLE 这四种事务隔离级别所提供的事务一致性是越来越强的,但是并发性却是却来越差的。
第二部分:事务隔离级别
提到事务隔离级别就必须先明确以下三种读:
脏读:读到了其他事务已修改但未提交的数据
不可重复读:由于其他事务的修改,导致同一事务中两次查询读到的数据不同
幻读:由于其他事务的修改,导致同一事务中两次查询读到的记录数不同
不可重复读:由于其他事务的修改,导致同一事务中两次查询读到的数据不同
幻读:由于其他事务的修改,导致同一事务中两次查询读到的记录数不同
1.READ UNCOMMITTED
这种隔离级别下 select 语句是不加事务锁的,因此会产生脏读,这种事务隔离级别是应当完全避免的。除 select 语句以外的其他语句加锁模式与 READ COMMITTED 一样。
2.READ COMMITTED
同 REPEATABLE READ 一样,这种隔离级别下也实现了一致性非锁定读,但区别在于此隔离级别下的一致性读是语句级的,即只能避免脏读,不能避免不可重复读和幻读。其实现方式大致是:
- select 语句检测要锁定的索引记录上是否有独占锁。
- 如果有独占锁那么到 undo 中寻找最近的前镜像。
- 如果没有独占锁那么添加 S 模式的 record lock。
在这种隔离级别下,InnoDB 只使用 record lock 类型的行锁,不使用 gap 锁。
此外:如果你使用 READ COMMITTED 事物隔离级别,那么 binlog 模式必须修改为 row 模式!
关于具体的 MVCC 实现方式,MySQL 官网并未提供具体的实现步骤,可以选择去查看源码,也可以参考 Oracle 和 SQL Server 的实现机制。
3.REPEATABLE READ
这是 MySQL 的默认事务隔离级别。在一个事务当中第一次读会建立一个 snapshot,同事务的相同 select 语句会读取这个 snapshot 来实现一致性非锁定读。
这种隔离级别下可以避免脏读、不可重复读和幻读。
对于 select for update/select lock in share mode/update/delete 这些锁定读,加行锁模式取决于索引的类型:
- 对唯一索引的访问只会添加 record lock,而不会使用 gap lock(即也没有 next-key lock)。
- 对非唯一索引的访问使用 gap lock 或者 next-key lock,如果访问的记录不存在就是 gap lock,否则就是 next-key lock。
4.SERIALIZABLE
这种事务隔离级下 select 语句即便不加 lock in share mode 也使用 lock_mode= S 的行锁,select 自成事务,锁直到事务结束才释放。
这种隔离级别下可以避免脏读、不可重复读和幻读。
DML 语句的加锁模式与 REPEATABLE READ 一样。
第三部分:总结
一般来说我们没必要去修改默认的事务隔离级别,当然如果你的数据库并不在意幻读和不可重复读,可以修改未 read committed 隔离级别,这样可以增加并发减少阻塞,据说淘宝也是这么干的。Oracle 默认的事务隔离级别也是 read committed,同样不可避免幻读和不可重复读。
关于 MySQL 的锁机制,可以参考:https://www.linuxidc.com/Linux/2018-04/151914.htm
正文完
星哥玩云-微信公众号