Mysql中的锁

247 阅读4分钟

在mysql中如果需要修改一行数据那么会先看有没有被加锁,如果没有自己会创建一个锁里面包含(事务id、等待状态)然后把锁跟着行数据关联起来。同时我们更新的数据必须把数据页加载到内存中所以这行需要更新的数据和关联的锁结构都是在内存里发生的。 现在事务B来了准备修改这一行数据发现事务A已经加锁了,所以他只有加锁然后等待 这里的锁状态是2说明在等待,而事务A的锁状态是false所以正在进行修改。 如果这个时候事务A 修改完了它会释放掉自己的锁,然后查看是否有别的事务也在对这个数据加锁,发现了事务B然后把事务B的锁状态改为false,让事务B运行。

独占锁与共享锁

上面我们介绍了如果多个事务更新同一行数据只能有一个事务加上上独占锁,其他事务也只能加独占锁然后在后面等待。那么现在有事务需要读取这个数据需要等待吗?答案是:不用的。因为这个时候直接就触发MVCC机制了。也就是说我们读取数据和写入数据是不互斥的,mvcc就是为了解决这个问题的。此时读取数据完全可以根据你ReadView去undoLog 链找到一个版本快照来使用。这种多个事务更新数据加的独占锁称为X锁。 如果我们查询的时候也想要加锁怎么办? 可以加共享锁就是S锁。但是S锁和X锁不能同时存在,因为我们更新数据的事务已经加了独占锁了,这个时候你想查询的时候加共享锁。就需要等待了。 如:

select * from User lock in share mode

那么如果别人加了共享锁, 你来更新数据加独占锁也是只能等待因为锁与锁是互斥的。当然我们查询的时候走MVCC机制默认是不加锁的。

锁类型独占锁共享锁
独占锁互斥互斥
共享锁互斥不互斥

从表格中可以看出 共享锁就是S锁与S锁间不互斥 另外查询的时候也可以加X锁 也就是独占锁

select * from users for update

只要你加了独占锁 只能等你事务执行完成才可以让别人操作数据。在多个事务操作数据的更新数据的时候都需要加独占锁所以不会出现脏写的情况。一个事务完成后才会事务锁然后唤醒下一个事务更新数据。

表锁

Mysql中为表加锁是很鸡肋的东西,表锁分为:表级共享锁、表级独占锁加锁方式如下:

LOCK TABLE 表名 READ (表级共享锁)
LOCK TABLE 表民 WRITE (表级独占锁)

一般来说没人去加表锁这种事没事找事,所以很鸡肋的。 还有两种情况会加表锁。

  1. 如果有事务在表里更新数据会加那么会在行级加独占锁,同时会在表级加意向独占锁。
  2. 如果有事务在表里执行查询操作,那么会加表级意向共享锁 其实我们平时操作表比较常见的锁反而是表级的意向共享锁和表级意向独占锁,但是意向锁间不互斥。
锁类型独占锁意向独占锁共享锁意向共享锁
独占锁互斥互斥互斥互斥
意向独占锁互斥不互斥互斥不互斥
共享锁互斥互斥不互斥不互斥
意向共享锁互斥不互斥不互斥不互斥

从上表可知如果你主动添加表级独占锁会跟更新数据自动添加的表级意向独占锁互斥,这个时候没人可以更新这个表了。所以一般来说我们更新表里的数据对目标行添加独占锁, 读取数据的话就走MVCC多版本并发机制了。不会影响你修改数据的。