NoteDeep

事务的隔离级别



Read Uncommited(未提交读)
Read Commited (提交读)
Repeatable Read (可重复读)
Serializable (可串行化)
脏读
Possible
Not Possible
Not Possible
Not Possible
不可重复读
Possible
Possible
Not Possible
Not Possible
幻行
Possible
Possible
Possible
Not Possible

(从上往下依次增加,较低的隔离级别通常支持较高的并发,系统的开销也更低。因为隔离级别是通过影响锁策略和其他机制去实现效果的,上锁是需要开销的)

事务隔离是数据库处理的基础之一。隔离级别是在多个事务同时进行更改和执行查询时,对结果的性能和可靠性,一致性和可重复性之间的平衡进行微调的设置。
用户可以使用SET TRANSACTION语句更改单个会话或所有后续连接的隔离级别。

InnoDB使用不同的锁策略支持每个隔离级别。您可以使用默认的REPEATABLE READ级别强制执行高度一致性操作。或者可以放宽一致性规则,即READ COMMITTED或READ UNCOMMITTED。在这种情况下,能最小化锁的开销,但是会降低精确的一致性。 SERIALIZABLE强制执行比REPEATABLE READ更严格的规则,主要用于特殊情况,例如XA事务以及排除并发和死锁问题。


以下列表描述了MySQL如何支持不同的事务级别。
该列表从最常用的级别到最少使用的级别。

可重复读 REPEATABLE READ

这是InnoDB的默认隔离级别。在同一事务中,读取由第一次读取建立的快照。这意味着如果在同一个事务中发出几个纯的(非锁定的)SELECT语句,重复执行同样的查询结果相同。
  • 对于具有唯一搜索条件的唯一索引,InnoDB只锁定找到的索引记录,而不是锁定之前的间隔。
  • 对于其他搜索条件,InnoDB锁定扫描的索引范围,使用gap lock或next-key lock阻止其他会话的插入到范围覆盖的间隙
InnoDB会为您的事务提供一个时间点,根据该时间点查询数据库。如果另一个删除一行的事务在您的时间点之后提交,则不会将该行视为已被删除。插入和更新也是如此。

例子:
Session A Session B

SET autocommit=0; SET autocommit=0;
time
| SELECT * FROM t;
| empty set
| INSERT INTO t VALUES (1, 2);
|
v SELECT * FROM t;
empty set
COMMIT;

SELECT * FROM t;
empty set

COMMIT;

SELECT * FROM t;
---------------------
| 1 | 2 |
---------------------

如果要查看数据库的“最新”状态,请使用READ COMMITTED隔离级别

提交读 READ COMMITTED

即使在同一事务中,每次查询都会读取自己的新快照。

UPDATE语句和DELETE语句,InnoDB只锁定索引记录,而不锁定之前的间隔。允许在锁定记录旁边自由插入新记录。
因为禁用了gap lock,所以可能会出现“幻行”,因为其他事务可以将新行插入到间隙中。
  • 对于UPDATE或DELETE语句,InnoDB仅为更新或删除的行保存锁。在MySQL评估WHERE条件之后,释放对不匹配行的记录锁定。大大降低了死锁的可能性。
例子:
插入数据:
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2); COMMIT;

第一个update语句:
SET autocommit = 0;
UPDATE t SET b = 5 WHERE b = 3;

第二个:
SET autocommit = 0;
UPDATE t SET b = 4 WHERE b = 2;

当使用默认的REPEATABLE READ隔离级别时,第一个UPDATE会把5条记录全部锁上X锁:
x-lock(1,2); retain x-lock
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); retain x-lock
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); retain x-lock

第二个update在这种情况下必须等待第一个update执行完毕,并且释放锁之后,才能获取它的锁。


如果是 READ COMMITTED 级别,第一个UPDATE获取x锁之后,会释放那些不修改的行:
x-lock(1,2); unlock(1,2)
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); unlock(3,2)
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); unlock(5,2)

脏读 READ UNCOMMITTED

事务可以读取未提交的数据,也称脏读。非常可怕,基本不会使用这一级别。

可串行化 Serializable

最高的隔离级别,它强制事务串行执行。会导致大量的超时和锁争用问题。虽然数据一致性好,但是并发能力很弱,一般也很少使用。











评论列表

    事务的隔离级别
    可重复读 REPEATABLE READ
    提交读 READ COMMITTED
    脏读 READ UNCOMMITTED
    可串行化 Serializable