• MySQL事务隔离级别


    参考自:https://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-isolation-levels.html

    第一部分:概述
    InnoDB遵循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-isolation启动项或者将其写入配置文件,来设置相应的全局事务隔离级别。
    READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ和SERIALIZABLE这四种事务隔离级别所提供的事务一致性是越来越强的,但是并发性却是却来越差的。
     
    第二部分:事务隔离级别
    提到事务隔离级别就必须先明确以下三种读:
    脏读:读到了其他事务已修改但未提交的数据
    不可重复读:由于其他事务的修改,导致同一事务中两次查询读到的数据不同
    幻读:由于其他事务的修改,导致同一事务中两次查询读到的记录数不同
    1.READ UNCOMMITTED
    这种隔离级别下普通select语句是不加事务锁的,因此会产生脏读,这种事务隔离级别是应当完全避免的。除select语句以外的其他语句加锁模式与READ COMMITTED一样。
    2.READ COMMITTED
    同REPEATABLE READ一样,这种隔离级别下也实现了一致性非锁定读,但区别在于此隔离级别下的一致性读是语句级的,即只能避免脏读,不能避免不可重复读和幻读。其实现方式大致是:
    • 一致性非锁定读的select语句检测要锁定的索引记录上是否有独占锁(在server层也会添加S模式的record lock,此锁为server层的元数据库锁,非innodb事务锁)。
    • 如果有独占锁那么到undo中寻找最近的前镜像。
    • 如果没有独占锁那么直接读取数据。
    在这种隔离级别下,InnoDB的锁定读(SELECT with FOR UPDATE or LOCK IN SHARE MODE)只使用record lock类型的行锁,不使用gap锁。
    此外:如果你使用READ COMMITTED事物隔离级别,那么binlog模式必须修改为row模式!
    关于具体的MVCC实现方式,MySQL官网并未提供具体的实现步骤,可以选择去查看源码,也可以参考Oracle和SQL Server的实现机制。
    3.REPEATABLE READ
    这是MySQL的默认事务隔离级别。在一个事务当中第一次读会建立一个全库snapshot,同事务下的select语句会读取这个snapshot来实现一致性非锁定读。而第一个snapshot的建立猜测与READ COMMITTED下的读取机制一样。同事务的select语句会读取这个snapshot的数据来实现一致性非锁定读,这个snapshot是针对整个数据库中所有支持MVCC机制的表的,即在snapshot建立后读取任意其他表都只会读取到snapshot中的快照数据,示例如下:

    时刻一,A会话执行:select * from T2 where id=1;
    时刻二,A会话执行:start transaction; select * from T1; --snapshot建立
    时刻三,B会话执行:针对T1表和T2表的DML语句修改数据
    时刻四,A会话执行:select * from T1; --发现读到的数据与时刻二一模一样,证明表T1实现了一致性读
    时刻五,A会话执行:select * from T2 where id=1; --发现读到的数据与时刻一一致,证明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一样。
    官网对于这个隔离级别的解释是只有将autocommit设置为0后select才会被隐式转换为lock in share mode的加锁模式,但是经测验发现在此模式下只要为select语句开启事务就会阻塞其他事物的更改,因此官网解释应该有误。
     
    第三部分:总结
    一般来说我们没必要去修改默认的事务隔离级别,因为修改事务隔离级别为read commited对于性能并无明显提升。当然如果你的数据库并不在意幻读和不可重复读,可以修改为read committed隔离级别,这样可以略微的增加并发减少阻塞,据说淘宝也是这么干的,Oracle默认的事务隔离级别也是read committed,同样不可避免幻读和不可重复读。
    此外需要注意的是如果想要Innodb支持全局分布式事务,那么事物隔离级别最好设置为serializable read,且innodb_support_xa项必须为1(另外为确保innodb的二阶段日志提交innodb_support_xa也是必须开启的,这其实是一种内部的分布式机制但无需serializable read的隔离级别)。
    关于MySQL的锁机制,可以参考:http://www.cnblogs.com/leohahah/p/8862216.html
    其他:
    关于一致性非锁定读和锁定读的解释,详见MySQL各类SQL语句的加锁机制
  • 相关阅读:
    Python3.x和Python2.x的区别
    urllib库python2和python3具体区别
    Oracle实现自增方式:序列+触发器
    菜单
    visual studio 2013连接Oracle 11g并获取数据:(二:实现)
    Oracle连接出现TNS:no listener或者ORA-12514: TNS:listener does not currently know
    visual studio 2013连接Oracle 11g并获取数据:(一:环境搭建)
    C#编程
    Oracle 11g 安装
    Android在Eclipse上的环境配置
  • 原文地址:https://www.cnblogs.com/leohahah/p/8857124.html
Copyright © 2020-2023  润新知