• MySQL-事务隔离-2


    事务隔离级别

    事务隔离是数据处理的基础能力之一,隔离是指ACID中的I(isolation的首字母大写)。当同时存在多个事务执行更新操作、执行查询操作的时候,隔离级别能提供设置用于优化调整性能与可靠性、一致性、结果可重现性之间的平衡。

    InnoDB提供4个事务隔离级别,是由SQL:1992标准制订,其包括读未提交(READ UNCOMMITTED)、读提交(READ COMMITTED)、可重复读(REPEATABLE READ)、可串行化(SERIALIZABLE),InnoDB的默认隔离级别是可重复读。

    用户可以手动设置事务隔离级别,使用的语句是SET TRANSACTION,该语句可以改变当前会话的事务隔离级别,并且后续所有的连接都使用新设置的事务隔离级别,用户也可以使用命令行的参数或者配置文件设置事务隔离级别,其形式是--transaction-isolation。

    InnoDB使用不同的锁策略支持不同的事务隔离级别,默认的可重复读事务隔离级别能支持高度的一致性,保证在关键数据操作的时候能遵循重要的ACID规则。而读提交事务隔离级别、读未提交事务隔离级别能支持更加宽松的一致性,保证锁机制带来最小的系统资源开销。可串行化事务隔离级别比可重复读事务隔离级别的规则要求更加严格,其主要用在一些特殊的场景中,例如,XA类型的分布式事务、解决一致性与deadlocks的问题。如下所示,列举并详细说明InnoDB的事务隔离级别,最常用的排在前面:

    可重复读

    InnoDB的默认事务隔离级别,在同一个事务中的一致性读是读取由第一次读确立的快照,也就是,在同一个事务中执行多个SELECT的语句(无锁类型的读),则这些SELECT语句获取到的结果值是相互一致的。

    有锁类型的读(SELECT FOR UPDATE 或者SELECT FOR SHARE)、更新、删除语句,锁的实现方式依赖于具体的语句是使用唯一性索引的唯一检索条件、还是范围类型的检索条件,其区别如下所示:

    • 对于唯一性索引的唯一检索条件,InnoDB只是锁住该索引记录,而没有锁住索引记录之前的地址间隙

    • 对于其他检索条件,InnoDB锁住扫描的索引范围,使用间隙锁或者下一键锁阻塞其他会话在该索引范围内的间隙中插入记录

    读提交

    每次一致性读,即使在同一个事务中,读或者设置只是读到该次读自身对应的快照。

    有锁类型的读(SELECT FOR UPDATE 或者SELECT FOR SHARE)、更新、删除语句,InnoDB只是锁住索引记录,而没有锁住索引记录之前的地址间隙,因而,允许插入新记录到索引记录相邻位置中,间隙锁只是用于外键约束检查或者用于重复键的检查。

    因为没有使用间隙锁,所以其他会话可以插入新记录到间隙中,因而会出现幻读。

    只有基于行的二进制日志支持读提交,如果用户使用读提交与binlog_format=MIXED配置项,则InnoDB自动地使用基于行的日志。

    此外,使用读提交也会产生额外的影响,如下所示:

    • 对于更新或者删除语句,InnoDB只是持有更新或者删除对应的行记录的锁,不匹配条件的行记录的锁将被释放,该机制极大地降低出现deadlocks的可能性,但是也不排除出现deadlocks的可能

    • 对于更新语句,如果一行记录已经被锁住了,则InnoDB执行半一致性读,即返回最新被提交的数据版本,MySQL将根据返回的数据版本确定是否匹配更新的条件,如果匹配更新条件,MySQL将再一次读取更新之后的行记录,再次读取之后,InnoDB将锁住或者等待锁住更新之后的行记录

    假设,存在以下的数据表:

    如上所示,数据表t没有建立索引,所以,检索与索引扫描都使用隐藏的主键索引而不是索引列执行记录锁。

    假设,存在一个会话A执行一个更新操作:

    假设,随后存在一个会话B执行一个更新操作:

    当InnoDB执行一个更新的时候,首先对每一个行记录获取一个排他锁,然后,确定是否需要更新该行记录,如果InnoDB不需要更新该行记录,则释放该行对应的排他锁,否则,InnoDB将持有该排他锁直到事务结束。

    当使用可重复读的事务隔离级别,会话A将获取到读到的每行记录的排他锁,在事务结束之前都不会释放这些排他锁,该隔离级别对事务提交的影响如下所示:

    会话B不能获取到任何的排他锁而阻塞,因为前面的会话A已经锁住了全部的行记录(持有所有行记录的排他锁),因此,会话B阻塞等待直到会话A提交事务或者执行事务回滚,该隔离级别对事务提交的影响如下所示:

    当使用读提交的事务隔离级别,会话A将获取到读到的每行记录的排他锁,而不需要更新的行记录的排他锁将被立刻释放(不匹配到更新条件的行记录),该隔离级别对事务提交的影响如下所示:

    会话B执行半一致性读,其返回每行记录的最新已提交的数据版本,MySQL根据返回的数据版本确定是否匹配符合更新的条件,该隔离级别对事务提交的影响如下所示:

    然而,假如更新条件中包括一个索引列,则InnoDB使用该唯一的索引列作为记录锁获取与维持,如下所示,会话A与会话B都使用b的值等于2的索引列作为记录锁获取与维持:

    读提交的事务隔离级别可以在MySQL服务器启动之前设置,在完成启动后生效,也可以在MySQL服务器正常运行中设置,也可以设置对所有的会话生效,也可以设置只对单个会话生效。

    读未提交

    该事务隔离级别是以无锁的方式实现,因此,在数据检索的过程中不能保证读一致性,很有可能读到一个早期的已经提交的数据版本,该方式被称之为脏读。

    可串行化

    该事务隔离级别类似于可重复读,如果自动提交事务的开关被打开,则所有的SELECT都被转换成SELECT FOR SHARE的方式,其使用无阻塞的方式实现串行化的一致性读,如果自动提交事务的开关被关闭,其使用阻塞式的方式实现一致性读。

    (未完待续)

  • 相关阅读:
    LeetCoded贪心算法系列——455.分发饼干
    第四十三章 持久对象和SQL - 查看存储的数据
    基于卷积神经网络与双向长短时融合的锂离子电池剩余使用寿命预测
    netty系列之:netty中的frame解码器
    云原生服务无状态(Stateless)特性的实现
    Java内存溢出(OOM)分析
    C. Boboniu and Bit Operations(暴力+枚举)
    2个月的时间备考PMP时间够用吗?
    牛客题目——最长公共子串、最长回文子串、兑换零钱
    TCR历史研究夏校申请详解
  • 原文地址:https://blog.csdn.net/uesowys/article/details/127802861