前言
隔离级别的出现是为了解决多事务并发情况下可能会产生的几种异常情况,分别是 更新丢失(Lost Update)、脏读(Drity Read)、不可重复度(Non-repeatable Read)、幻读(Phantom Read)。
解决问题
更新丢失(Lost Update) 通常会出现于两种情况:回滚丢失和覆盖丢失。
脏读(Drity Read): 又称无效数据读,即读取未提交数据,一个事务读取另外一个事务还没有提交的数据叫脏读。 总结为:读取未提交数据。
不可重复读(Non-repeatable Read): 即在同一个事务内,相同的查询多次返回结果是不一致的。 总结为:事务中多次读取,数据内容不一致。
幻读(Phantom Read): 总结为:事务中多次读取,数据总量不一致
其中不可重复度和幻读可能有些人认为是同样的问题,其实是不一样的。不可重复读侧重于记录的修改,幻读侧重于记录的新增或删除。
标准SQL定义了四种隔离级别,用于解决上面几种问题、支持事务的实现。分别是:读取未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeatable Read)、串行化(Serializable)。
其中各种隔离级别所能解决上述问题的支持情况如下表所示(Yes代表能解决;No代表不能解决):
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读取未提交(Read Uncommitted) | No | No | No |
| 读提交(Read Committed) | Yes | No | No |
| 可重复读(Repeatable Read) | Yes | Yes | No |
| 串行化(Serializable) | Yes | Yes | Yes |
其中可重复读(Repeatable Read) 可用了临键锁 + MVCC解决了幻读现象,下文在讲解。
浅谈隔离级别
Read Uncommitted(读未提交) 即事务间可相互读取其他事务没有提交的数据,往往会引发脏读问题。该隔离级别整体优势不是很明显,故并不常用于实际生产中。了解即可。
Read Committed(读提交) 即可读取其它事务提交的数据,部分关系型数据库默认的隔离界别(如:Oracle)。但是往往会出现 不可重复读 问题,即事务不同阶段对同一记录读取到的值是不相同的。
Repeatable Read(可重复读) 即使用视图保证事务过程中同一记录的一致,但是不能避免 幻读 问题的产生。该隔离级别是 MySQL (innodb、Falcon)默认隔离级别,通常使用MVCC + 临键锁来避免幻读产生。
Serializable(串行化) 即使用对数据加锁(共享、排他)实现是数据记录操作的串行执行,可解决脏读、不可重复的、幻读的问题。一致性最高但性能相对不高。
查看隔离级别
MySQL 默认的隔离级别是 可重复读,可以使用以下语句进行查看。
select @@session.tx_isolation;
select @@global.tx_isolation;
# MySQL8 之后也可使用下面语句查看
select @@session.transaction_isolation;
select @@global.transaction_isolation;
设置隔离级别
# 可选级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE
# 会话级别
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
# 全局级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ