美文网首页
[译]事务隔离级别

[译]事务隔离级别

作者: wangjie_yy | 来源:发表于2017-09-16 10:58 被阅读18次

原文地址Transaction Isolation Levels

事务隔离级别

事务隔离是数据库基础能力之一。隔离(Isolation)表示ACID中的I;隔离级别是一个配置项,它可以用于调整当多个事务同时进行更新和查询操作时,MySQL的性能和可靠性、一致性、结果的可重复性之间的平衡。

InnoDB提供了四种隔离级别,SQL:1992标准中描述了这个四个级别:未提交读(READ_UNCOMMITTED),提交读(READ_COMMITTED),可重复读(REPEATABLE_READ),串行化(SERIALIZABLE)。InnoDB的默认级别是可重复读(REPEATABLE_READ)。

用户可以使用SET_TRANSACTION语句来更改当前会话中的隔离级别。如果要更改全局的隔离级别,对所有会话生效,在命令行或者配置文件中使用--transaction-isolation选项。更多隔离级别的设置语法,可以查看SET TRANSACTION Syntax

InnoDB使用不同的锁机制来实现上述不同的隔离级别。对于需要保证ACID重要数据上的操作,可以使用默认的REPEATABLE_READ实现高级别的一致性。对于精确的一致性和结果可重复性要求不那么高的情形,比如大量数据的操作,减少锁的数量更加重要,这种情况下可以使用READ_COMMITTED甚至READ_UNCOMMITTED来降低一致性。SERIALIZABLE实现了比REPEATED_READ更严格的规则,它主要用于一些特殊的场合,比如XA事务,以及解决并发和死锁相关问题。

以下描述了MySQL如何支持不同的隔离级别。顺序按照最常用到最不常用的。

  • REPEATED READ

    这是InnoDB的默认隔离级别,同一个事务中的连续读(Consistent reads)会读到第一个读操作建立的快照(snapshot)。这也就是说如果在同一个事务中进行简单的多次SELECT操作,这些操作相互是一致的。更多可以查看一致无锁读(Consistent Nonlocking Reads)。

    对于加锁读(SELECT with FOR UPDATE or LOCK IN SHARE MODE)、UPDATEDELETE等操作,锁取决于操作语句是否使用了唯一索引并且使用唯一检索条件,还是使用了范围检索条件。

    • 对于使用唯一索引并且使用唯一检索条件的情形,InnoDB只会给指定的这行记录索引加锁,不会在前面的间隙上枷锁。
    • 对于使用范围检索条件的情形,InnoDB会给扫描到的索引范围都加上锁,使用间隙锁next-key锁来阻止其他会话往这个范围内插入数据。有关间隙锁和next-key锁,可以查看InnoDB Locking
  • READ COMMITTED

    这个级别下,在同一个事务中的连续读操作,每一个读都会设置自己独有的最新快照并从中读取数据。有关连续读操作,查看Consistent Nonlocking Reads

    对于加锁读(SELECT with FOR UPDATE or LOCK IN SHARE MODE)、UPDATEDELETE等操作,InnoDB只会给索引记录加锁,而不会给记录前面的间隙加锁,这样就允许了其他事务往这些记录间插入数据。间隙锁只会用来做外键约束检查以及重复key检查。

    由于没有使用间隙锁,会出现幻读问题,因为其他会话可能往间隙中插入了数据。有关幻读,查看Phantom Rows

    如果你使用了READ COMMITTED级别,你必须同时使用行级别的二进制日志。

    使用READ COMMITTED级别还有其他的影响:

    • 对于UPDATEDELETE语句,InnoDB会锁住将要更新或者删除的行。MySQL计算WHERE语句后,就会把不匹配的行上的锁释放掉。这个大大降低了死锁的概率,但是仍然有可能会发生。
    • 对于UPDATE操作,如果记录已经被锁住,InnoDB会做"半一致性(semi-consistent)"读,它返回最近一次提交版本的记录给MySQL,然后MySQL会决定这个记录是否和UPDATE语句的WHERE条件匹配。如果记录匹配(需要被更新),MySQL会重新读取这行记录,并且不会加锁也不等待锁。

    考虑下面这个例子,先建立一个表:

    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;
    

    在这种情况下,表没有索引,因此查找和索引遍历操作会使用隐藏的聚合索引来给记录加锁(查看Clustered and Secondary Indexes)。
    假设此时一个用户使用如下语句进行UPDATE操作:

    SET autocommit = 0;
    UPDATE t SET b = 5 WHERE b = 3;
    

    紧接着,另外一个用户使用如下语句进行UPDATE操作:

    SET autocommit = 0;
    UPDATE t SET b = 4 WHERE b = 2;
    

    InnoDB执行这些UPDATE时,会先对每一行都加上排它锁,然后决定是否更改它们。如果InnoDB没有修改这些行,那么会立即立即释放锁;否则,InnoDB会持有锁直到事务结束。这样的操作对事务处理的影响如下:

    当使用默认的REPEATABLE READ级别时,如果第一个UPDATE拿到了排它锁,并且没有释放任何一个:

    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锁住了所有的行)的锁时都会阻塞,知道第一个UPDATE操作提交或者回滚:

    x-lock(1,2); block and wait for first UPDATE to commit or roll back
    

    当使用READ COMMITTED级别时,第一个UPDATE操作获取排他锁,并且立即释放它不修改的行的锁:

    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)
    

    对于第二个UPDATE,InnoDB会做"半一致性(semi-consistent)"读,它返回最近一次提交版本的记录给MySQL,然后MySQL会决定这个记录是否和UPDATE语句的WHERE条件匹配:

    x-lock(1,2); update(1,2) to (1,4); retain x-lock
    x-lock(2,3); unlock(2,3)
    x-lock(3,2); update(3,2) to (3,4); retain x-lock
    x-lock(4,3); unlock(4,3)
    x-lock(5,2); update(5,2) to (5,4); retain x-lock
    

    使用READ COMMITTED隔离级别的效果和被废弃的innodb_locks_unsafe_for_binlog配置项是一样的,除了以下两点:

    • 设置innodb_locks_unsafe_for_binlog是一个全局的配置,会影响所有的会话。但隔离级别可以选择设置为对所有会话有效或者对单个会话有效。
    • innodb_locks_unsafe_for_binlog只能在服务启动时的时候设置。但隔离级别可以在启动时和运行时设置。
  • READ UNCOMMITTED

    SELECT操作使用不加锁的方式,不过有可能会返回较早的版本数据。因此使用这种级别时,读取是不一致的。这个也叫做脏读。除此之外,这个级别和READ COMMITTED级别一样。

  • SERIALIZABLE

    这个级别和REPEATED READ级别类似,不同地方在于,如果autocommit没有设置,InnoDB会隐世的把SELECT转换为SELECT ... LOCK IN SHARE MODE。如果autocommit设置了,SELECT就是一个事务。It therefore is known to be read only and can be serialized if performed as a consistent (nonlocking) read and need not block for other transactions.(不会翻译-_-||)(如果想要在有其他事务修改数据时阻塞住当前[SELECT]操作,不要设置autocommit)

相关文章

  • [译]事务隔离级别

    原文地址Transaction Isolation Levels 事务隔离级别 事务隔离是数据库基础能力之一。隔离...

  • Spring 中的事务隔离级别

    什么是事务隔离级别? 事务隔离级别是对事务 4 大特性中隔离性的具体体现,使用事务隔离级别可以控制并发事务在同时执...

  • MySQL_tx_isolation

    事务隔离级别 一、数据库事务隔离级别数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、...

  • MySQL事务隔离级别和实现原理,看这一篇就够了!!!

    经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗,事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么...

  • 面试题

    基础知识 1、事务隔离级别 补充: 1、事务隔离级别为读提交时,写数据只会锁住相应的行 2、事务隔离级别为可重复读...

  • 数据库事务相关

    事务隔离级别(tx_isolation)mysql 有四级事务隔离级别 每个级别都有字符或数字编号 级别symbo...

  • 关于Spring的事务Transactional,锁同步,并发线

    Spring事务传播机制和数据库隔离级别 在标准SQL规范中定义了4个事务隔离级别,不同隔离级别对事务处理不同 。...

  • Mysql事务

    事务隔离级别 事务隔离级别有四种:read-uncomitted,read-commited,repeatable...

  • mysql事务-2020-11-21

    use test查询事务隔离级别:select @@tx_isolation; 设置事务隔离级别://全局的set...

  • MYSQL事务

    常用语句 MYSQL事务,锁表 事务控制语句 事务的隔离级别 隔离级别描述产生风险READUNCOMMITTED ...

网友评论

      本文标题:[译]事务隔离级别

      本文链接:https://www.haomeiwen.com/subject/layysxtx.html