前情提要

当多个事务同时更新一条数据的时候,如何防止脏写的问题

锁机制的引入

依靠锁机制让多个事务更新同一行数据的时候串行化,避免同时更新。

锁机制下的更新步骤

  1. 事务A要更新一条数据,先判断当前数据是否有锁。没锁则当前事务创建一个锁,其中包含了自己的trx_id和等待状态,然后把锁和数据关联起来。
  2. 此时数据和锁都是在内存中。
  3. 事务B也要更新这条数据,检查数据是否有锁时发现存在着事务A创建的锁。则创建了属于自己的一个锁,其中等待状态为true。表示正在等待
  4. 事务A更新完后,释放锁,然后寻找到事务B对这条数据加锁了。此时就会把事务B的锁中的等待状态修改为false,然后唤醒事务B。

行锁

独占锁

简介

又叫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 日
如果觉得我的文章对你有用,请点个赞吧~