zoukankan      html  css  js  c++  java
  • mysql事务隔离级别

    事务特性定义acid

    • 原子性(A):事务是最小单位,不可再分
    • 一致性©:事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败
    • 隔离性(I):事务A和事务B之间具有隔离性
    • 持久性(D):是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)

    隔离级别

    • 读未提交:read uncommitted
    • 读已提交:read committed
    • 可重复读:repeatable read
    • 串行化:serializable

    出现问题

    • 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
    • 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。强调是读读场景
    • 幻读(Phantom Read):强调的是读写场景,在事物a中查询无记录后准备插入,在插入前b事务先插入并提交,导致a事务插入失败,此场景为幻读。

    解决问题


    其中mysl innodb引擎场景下通过next-key lock(行锁+gap锁)解决了rr级别的当前读的幻读问题,通过mvcc机制解决了rr级别的快照读的幻读问题


    mvcc

    是一个通用的解决方案的概念,目的是解决并发下数据库读写性能低下的问题,具体实现看各个厂商,具体到mysql的innoDB引擎中是通过快照读来实现mvcc,实现读写无锁化


    快照读

    • 像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。
    • 快照读本身也是一个抽象概念,再深入研究。MVCC模型在MySQL中的具体实现则是由 多个隐式字段,undo日志 ,Read View 等去完成的

    当前读

    像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。


    重点解析读已提交rc和可重复读rr


    读已提交rc

    • rc使用了mvcc机制,即有快照读,那么为什么依然会出现幻读和不可重复读的问题,这个取决于快照读中read view生成的时机,根据隔离级别的定义,rc下的read view在每一次select语句时都会新生成一个,所以可以读到当前时间点已提交的事务的最新数据,虽然保证了数据是最新的,但是同时带来在一个事务范围内同一条数据的内容发生变化的可能(不可重复读现象),也可能带来数据行数发生增加(幻读现象)
    • rc下的当前读同rr的当前读

    可重复读rr

    • rr使用了mvcc机制,即有快照读,那么为什么能解决幻读和不可重复读的问题,这个取决于快照读中read view生成的时机,根据隔离级别的定义,rr下的read view在事务中第一次select语句时会新生成一个,后续查询均采用该read view中的数据,所以可以读到的数据永远是第一次读到的(不同的查询语句当然不同,不予讨论)。虽然保证了数据读出来是不变的,但是依然不能避免其他事务做当前读操作导致的幻读,即rr读到的是旧的副本。算是为了提高并发读写场景下性能作出的牺牲吧,牺牲了一致性。
    • 但是rr在当前读场景下通过next-key lock(行锁+gap锁)解决了幻读问题,白话就是对范围内的数据行进行加锁,禁止其他事务并发写操作,也就不存在幻读问题了。
    • 常见用法场景:某个事务内需要先查询,后进行逻辑处理,最后更新数据库,这种一般先select where xx>a and xx<b for update,这样就锁住了a的上个位置到b的下个位置的数据(gap锁的定义,具体概念和细节需要额外展开讲,推荐看https://www.cnblogs.com/crazylqy/p/7611069.html)。但是缺点显而易见,锁的时间较长,取舍取决于业务。

    read view

    用来存储事务相关信息,包括事务id等等,具体数据存放在undo log中。


    实践

    mysql5.6版本
    select @@tx_isolation;
    select version();
    set session tx_isolation='repeatable-read';
    BEGIN;
    -- select * from sys_role;
    update sys_role set REMARK = 'for update3' where id = 22
    select * from sys_role where id = 23 for update
    COMMIT


    参考

    https://www.jianshu.com/p/8845ddca3b23
    https://www.cnblogs.com/jian-gao/p/10795407.html
    https://www.cnblogs.com/JMrLi/p/12705188.html

  • 相关阅读:
    union 和 union all 区别
    sql 日期类型空值等于 1900-01-01
    IDENTITY_INSERT 自增开关使用
    Convert.ToDateTime() 与 DateTime.TryParse()区别
    SOLID 原则摘录
    不同JavaScript 代码段 变量作用域
    sql 常见错误总结
    jquery.form插件 提交表单 type="hidden"取不到值的问题记录
    同义词
    SQL优化传送门
  • 原文地址:https://www.cnblogs.com/wish5714/p/14953559.html
Copyright © 2011-2022 走看看