ToB企服应用市场:ToB评测及商务社交产业平台

标题: MySQL 锁 [打印本页]

作者: 星球的眼睛    时间: 2024-9-2 15:36
标题: MySQL 锁
MySQL 锁

锁仅用于事务,当然咯,平时执行的单条SQL语句实在质也是事务。
共享锁(S锁,读锁)

当事务对某范围内的数据加上共享锁时,该事务可读数据,其他事务也可加上共享锁来读数据,但是全部事务均不能对数据进行修改。
   ⚠️tips
  我在开发时发现,如果仅有一个事务对某段数据加上共享锁,那么在 隔离级别是可重复读的前提下 ,此事务执行CRUD操作是可以乐成的。
  1. # 加锁
  2. SELECT * FROM [表] WHERE [条件] LOCK IN SHARE MODE;
  3. # 或(建议使用)
  4. SELECT * FROM [表] WHERE [条件] FOR SHARE;
复制代码
排它锁(X锁,写锁)

事务A和事务B同时开始执行,且两事务之间均有对某范围内的N条数据的修改操作。假如A事务首先拿到排它锁,那么事务B只能比及事务A释放排它锁以后才气获取到排它锁,进而执行CRUD操作,在未获取到排它锁之前,事务B的读操作可正常执行但CRUD操作将被阻塞
  1. # 加锁
  2. SELECT * FROM [表] WHERE [条件] FOR UPDATE;
复制代码
意向共享锁(IS锁)

意向共享锁是一种表级锁,只要一张表加上了共享锁,数据库引擎会主动为数据表加上意向共享锁,为什么MySQL要这么设计呢?由于我们的共享锁大多是锁的某范围内的数据,那么由上可知,共享锁与排他锁是互斥的,如果事务A对某范围内数据加了共享锁,事务B又来加排他锁,在没故意向锁的前提下MySQL引擎就会逐条逐条检查数据是否被加上共享锁或排它锁,这显然影响服从,所以当一张表中某范围内的数据被加上共享锁后,MySQL引擎主动给这张表加上 意向共享锁,代表此表有一定范围内的数据被加上了共享锁,那么事务B对此范围内的数据加排他锁时,首先验证表是否有被加意向共享锁,若加了,则不必大费周章去逐条检查数据了。
但若验证表的意向共享锁所锁定的范围内的数据与排它锁所锁定范围内的数据并无交集时,此表也可以加上排它锁。
意向排他锁(IX锁)

意向排他锁是一种表级锁,只要一张表加上了排他锁,数据库引擎会主动为数据表加上意向排他锁,MySQL为什么这么设计呢?同上!
但若验证表的意向排他锁所锁定的范围内的数据与当前事务的排它锁所锁定范围内的数据并无交集时,此表也可以再加上排它锁。
自增锁

自增锁是MySQL中一种特别的表级锁,专门用于处置惩罚自增字段(即具有AUTO_INCREMENT属性的列)的并发插入操作。这种锁的主要目标是确保在并发环境下,每个新插入的记录都能得到一个唯一的、递增的自增值。
但是自增锁管理的自增字段并不会由于回滚而恢复,例:现有一张表,自增id已经到了2,那么下一条数据的id应该3,现在事务A插入了10条数据,然后回滚,接着执行事务B插入一条数据,那么这条数据的自增id的值是13。
临键锁

例:事务中有SQL:select * from g_user where id > 8 and id < 20 for update;数据表g_user主键为id,表数据如下:
  1. +------+--------+------+
  2. | id   | g_name | age  |
  3. +------+--------+------+
  4. |    2 | user_2 |    2 |
  5. |    6 | user_6 |    6 |
  6. |    11| user_11|    11|
  7. ...略中间数据
  8. |   18 | user_18|    18|
  9. |   22 | user_22|    22|
  10. +------+--------+------+
复制代码
很显然,根据条件和数据可知表中并无id为8和20的数据,除了为此表加上排它锁以外,还需要一把锁来框定范围,那么MySQL是如那边理的呢?既然表中无id为8和20的数据那么MySQL引擎为此表加上一个临键锁,以此框定范围。
由上述数据可知:表中数据与8差值最少的是6,与20差值最小的是22,既然无id为18和20的数据,那么只能在6,22这俩数据上加锁了。即锁定id为6~22之间的数据。
加锁后,若另一事务插入了一条数据;阻塞环境如下
插入数据的id阻塞?缘故因由5no不在范围(8,20)范围内,介于6之前7yes​不在范围(8,20)范围内,但介于6之后21no不在范围(8,20)范围内,但介于22之前23yes不在范围(8,20)范围内,介于22之后 由此可知,间隙锁锁最右边隔断8最近的叶子节点,锁最左边隔断20最近的叶子节点,上述例子中是6与22,就是说6与22之间插入任何数据都会阻塞,即便它不处于(8,20)的范围之间。
间隙锁(GAP)

和临键锁雷同,也是锁某范围内的数据,但是按此范围的条件在表中并没有查询到数据,MySQL加的锁,就是临键锁。
例:事务中有SQL:select * from g_user where id > 7 and id < 10 for update;数据表g_user主键为id,表数据如下:
  1. +------+--------+------+
  2. | id   | g_name | age  |
  3. +------+--------+------+
  4. |    5 | user_5 |    5 |
  5. |    12| user_12|    12|
  6. +------+--------+------+
复制代码
很显然,根据条件和数据可知表中并无id处于7和10之间的数据,除了为此表加上排它锁以外,还需要一把锁来框定范围,那么MySQL是如那边理的呢?既然表中即无id处于7与10之间的数据,也无id=7和10的数据,那么MySQL引擎为此表加上一个间隙锁,以此框定范围。
由上述数据可知:表中数据与7差值最少的分别是5,与10差值最小的是12,既然无id为7和10的数据,那么只能在5和12这俩数据上加锁了。即锁定id为5,12这两条数据。
加锁后,若另一事务插入了一条数据;阻塞环境如下
插入数据的id阻塞?缘故因由4no不在范围(7,10)范围内,且介于5之前6yes​不在范围(7,10)范围内,但介于6之后11no不在范围(7,10)范围内,但介于12之前13yes不在范围(7,10)范围内,且介于12之后 由此可知,间隙锁锁最右边隔断id=5最近的叶子节点,锁最左边隔断id=10最近的叶子节点,上述例子中是5与12,就是说5与12之间插入任何数据都会阻塞,即便它不处于(7,10)的范围之间。
记录锁(REC_NOT_GAP)

按具体条件查询的某一条或几条数据,而不是按范围查询,MySQL对筛选出来的记录加上记录锁。
  1. # 例
  2. select * from g_user where id = 3 for update ;
  3. select * from g_user where id = 3 or id =4 or id =5 for update ;
  4. select * from g_user where id in (3,4,5) for update ;
  5. select * from tp where id between 1 and 5 for update ;
复制代码
检察锁的环境

  1. SELECT * FROM performance_schema.data_locks;
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4