【Mysql事务隔离级别与锁的关系

2023年 9月 27日 27.7k 0

mysql锁与事务隔离级别

前两篇文章我们

学了事务【Mysql】事务相关的问题 - 掘金 (juejin.cn),

学了锁【Mysql】mysql的锁 - 掘金 (juejin.cn),我以为稳了,结果今天被问对应关系,真的绷不住了。

事务

事务隔离级别有 读未提交,读已提交,可重复读,串行化。

会出现的问题

  • 脏读: 事务A读取数据,事务B修改数据未提交,事务A去读取,然后事务B回滚, 事务A读到了不存在的数据,这个叫脏读。

  • 不可重复读: 事务A读取数据,事务B修改数据并提交, 事务A再读取,前后读取获得的数据不一致

  • 幻读: 事务A读取数据,事务B插入数据并提交,事务A再读取,前后数据不一致

解决办法

image.png

mysql的锁有哪些:

具体的参照文章: 【Mysql】mysql的锁 - 掘金 (juejin.cn)

  • 全局锁, 这篇文章不涉及
  • 表锁: 为整个表上锁
  • 意向锁
  • 行锁
  • 记录锁
  • 间隙锁
  • 临键锁
  • 事务与锁的对应关系

    那么不同的隔离级别在读写时会加什么锁呢?

    读未提交隔离级别

    它会有脏读的问题,因为在读的时候是可以修改的,因此它的读写可同时进行,不会阻塞。

    直接select读的时候采用当前读: 读取的永远是最新的值,读取不会获得锁。

    修改:

    比如说:

    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    START TRANSACTION;
    UPDATE `book` set name = '小数' where id = 1001;
    

    这个时候会为id为1001的行添加行锁(以主键索引为查询条件): 会添加记录锁, 为表添加意向排它锁:

    image.png

    在「读未提交」隔离级别下,读写操作可以同时进行,但写写操作无法同时进行。与此同时,该隔离级别下只会使用行级别的记录锁,并不会用间隙锁。

    读已提交隔离级别

    读取数据: 同样不会获取锁,直接读取,每次读都会生成一个readview。

    修改数据: 会对指定行添加记录锁,然后全表的意向排它锁。不管是使用范围查询还是等值查询,都不会用到间隙锁。

    它和读未提交很像,但是它解决了脏读,因为它每次查询都是一次快照读,重建一个readview对象。

    可重复读隔离级别

    读取数据: 正常读取不会上锁,事务中第一次读取会获得readView对象。

    修改数据:

  • 使用主键索引等值查询: 只获取了记录锁,意向排它锁:
    image.png
    image.png

  • 使用主键索引范围查询: 获取了记录锁, 间隙锁, 意向排它锁
    image.png
    image.png

  • 搜索不存在的记录会加间隙锁。

  • 使用非主键索引等值查询: 下面例子可以看到用了意向排它锁,对1001的行锁,以及下一个区间的间隙锁。image.png
    image.png

  • 使用非主键索引范围查询: 因为锁的数据太多,退化为表锁,意向锁,行锁,及lock_data那里两行的临键锁,属于行锁与间隙锁的组合。

    我把非主键索引换成了version, 为了更好的范围查询。

    image.png

    image.png

  • Serializable隔离级别

    读取: 获得共享读锁

    修改: 与RR级别一致。

    总结

  • RU和RC只会用到行锁,用不到间隙锁。
  • RR隔离级别会使用行锁,可能用到间隙锁,临键锁
  • 串行化级别读也会加共享读锁,写的加锁方式与RR相同
  • 相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论