Loading... # 前情提要 当多个事务同时更新一条数据的时候,如何防止脏写的问题 # 锁机制的引入 依靠锁机制让多个事务更新同一行数据的时候串行化,避免同时更新。 # 锁机制下的更新步骤 1. 事务A要更新一条数据,先判断当前数据是否有锁。没锁则当前事务创建一个锁,其中包含了自己的trx_id和等待状态,然后把锁和数据关联起来。 2. 此时数据和锁都是在内存中。 3. 事务B也要更新这条数据,检查数据是否有锁时发现存在着事务A创建的锁。则创建了属于自己的一个锁,其中等待状态为true。表示正在等待 4. 事务A更新完后,释放锁,然后寻找到事务B对这条数据加锁了。此时就会把事务B的锁中的等待状态修改为false,然后唤醒事务B。 # 行锁 ## 独占锁 <!-- more --> ### 简介 又叫X锁,Exclude锁。当有一个事务加了独占锁后,其他事务再来更新当前数据,都是要加独占锁的,但是只能在独占锁后面等待。 ### 备注说明 当多事务更新同一行数据时,其他事物是能够直接读取这行数据的,并不需要加锁。因为默认开启mvcc机制可以基于ReadView去undo log版本链中找到一个能够读取的版本。 ## 共享锁 ### 简介 又叫S锁。语法是:SELECT * FROM TABLE **LOCK IN SHARE MODE**;意思是在查询的时候对一行数据加共享锁。 ### 备注说明 当一行数据加了X锁后,S锁是无法添加的,因为两者互斥。 当一行数据加了S锁后,其他事物也能添加S锁,因为S锁不互斥。 ### 其他情况 查询操作通过**LOCK IN SHARE** 添加共享锁; 查询操作通过**FOR UPDATE** 添加互斥锁; # 表锁 ## 语法 LOCK TABLES xxx READ;加表级共享锁(很少用) LOCK TABLES xxx WRITE;加表级独占锁(很少用) ## 其他加锁的操作 1. 如果有事务在表里执行增删改操作,就会在行级加独占锁。还会在表级加一个**意向独占锁**。 2. 如果事务在表里执行查询操作,那么会在表级添加一个**意向共享锁**。 ## 备注说明 1. 意向独占锁和意向共享锁不互斥 # 互斥关系 | 锁类型 | 独占锁 | 意向独占锁 | 共享锁 | 意向共享锁 | | ---------- | ------ | ---------- | ---------- | ---------- | | 独占锁 | 互斥 | 互斥 | 互斥 | 互斥 | | 意向独占锁 | 互斥 | **不互斥** | 互斥 | **不互斥** | | 共享锁 | 互斥 | 互斥 | **不互斥** | **不互斥** | | 意向共享锁 | 互斥 | **不互斥** | **不互斥** | **不互斥** | > 1. **独占锁与其他锁都互斥** > 2. 意向XX锁与意向XX锁之间不互斥 > 3. 共享锁,意向共享锁之间不互斥 > 4. 意向共享锁只与独占锁互斥 # 不确定性的性能抖动 ## 脏页刷盘 ### 原因分析 当一个查询语句,加载了大量的数据到缓存页中,导致内存中大量的缓存页被淘汰然后刷回磁盘。 ### 解决方案 减少缓存页刷盘的频率:增加buffer pool分配的内存空间 ## Redolog刷盘 ### 原因分析 redolog不断的写入,当日志文件写满了,就会对第一个日志文件进行覆盖写入,此时如果 第一个日志文件中的一些redolog 对应的内存里的缓存页的数据 如果还没有被刷回磁盘的话。也会触发脏页回盘的过程。 ### 解决方案 提升缓存页刷盘的速度 + 因为刷盘是典型的随机IO,所以要提升随机IO的性能,使用SSD固态硬盘。 + 配置参数innodb_io_capacity:采用多大的IO速率刷盘(每秒随机IO的次数) + 配置参数innodb_flush_neighbors:刷盘时把缓存页临近的其他缓存页也刷盘,但是这样刷回的缓存页就会变多,如果是SSD,把这个设置为0就行。 最后修改:2024 年 01 月 10 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请点个赞吧~