Mysql中的8中锁

8种锁

1 行锁(Record Locks)

2 间隙锁(Gap Locks)

间隙锁之间不相互排斥。不可以堵塞即唤起等待

3 临键锁(Next-key Locks)

4 共享锁/排他锁(Shared and Exclusive Locks)

意向锁是有数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享 / 排他锁之前,InooDB 会先获取该数据行所在在数据表的对应意向锁
如果另一个任务试图在该表级别上应用共享或排它锁,则受到由第一个任务控制的表级别意向锁的阻塞。第二个任务在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁

共享锁/排他锁都只是行锁,与间隙锁无关,这一点很重要,后面还会强调这一点。其中共享锁是一个事务并发读取某一行记录所需要持有的锁,比如select … in share mode;排他锁是一个事务并发更新或删除某一行记录所需要持有的锁,比如select … for update。

不过这里需要重点说明的是,尽管共享锁/排他锁是行锁,与间隙锁无关,但一个事务在请求共享锁/排他锁时,获取到的结果却可能是行锁,也可能是间隙锁,也可能是临键锁,这取决于数据库的隔离级别以及查询的数据是否存在。关于这一点,后面分析场景一和场景二的时候还会提到。

参考 https://juejin.im/post/6844903666332368909

5 意向共享锁/意向排他锁(Intention Shared and Exclusive Locks)

向共享锁/意向排他锁属于表锁,且取得意向共享锁/意向排他锁是取得共享锁/排他锁的前置条件

InnoDB为了让表锁和行锁共存而使用了意向锁。
举个粟子(此时假设行锁和表锁能共存): 事务A锁住表中的一行(写锁)。事务B锁住整个表(写锁)。

但你就会发现一个很明显的问题,事务A既然锁住了某一行,其他事务就不可能修改这一行。这与”事务B锁住整个表就能修改表中的任意一行“形成了冲突。所以,没有意向锁的时候,行锁与表锁共存就会存在问题!

事务 A 获取了某一行的排他锁,并未提交:

SELECT * FROM users WHERE id = 6 FOR UPDATE;

事务 B 想要获取 users 表的表锁:

LOCK TABLES users READ;

因为共享锁与排他锁互斥,所以事务 B 在视图对 users 表加共享锁的时候,必须保证:

  • 当前没有其他事务持有 users 表的排他锁。
  • 当前没有其他事务持有 users 表中任意一行的排他锁 。

为了检测是否满足第二个条件,事务 B 必须在确保 users表不存在任何排他锁的前提下,去检测表中的每一行是否存在排他锁。很明显这是一个效率很差的做法,但是有了意向锁之后,情况就不一样了:

意向锁的兼容互斥性

意向锁是怎么解决这个问题的呢?首先,我们需要知道意向锁之间的兼容互斥性:

意向共享锁(IS)意向排他锁(IX)
意向共享锁(IS)兼容兼容
意向排他锁(IX)兼容兼容

意向锁之间是互相兼容的,emmm…那你存在的意义是啥?

虽然意向锁和自家兄弟互相兼容,但是它会与普通的排他 / 共享锁互斥:

意向共享锁(IS)意向排他锁(IX)
共享锁(S)(表锁)兼容互斥
排他锁(X)(表锁)互斥互斥

注意:这里的排他 / 共享锁指的都是表锁!!!意向锁不会与行级的共享 / 排他锁互斥!!!

现在我们回到刚才 users 表的例子:

事务 A 获取了某一行的排他锁,并未提交:

SELECT * FROM users WHERE id = 6 FOR UPDATE;
复制代码

此时 users 表存在两把锁:users 表上的意向排他锁与 id 为 6 的数据行上的排他锁

事务 B 想要获取 users 表的共享锁:

LOCK TABLES users READ;
复制代码

此时事务 B 检测事务 A 持有 users 表的意向排他锁,就可以得知事务 A 必然持有该表中某些数据行的排他锁,那么事务 Busers 表的加锁请求就会被排斥(阻塞),而无需去检测表中的每一行数据是否存在排他锁。

意向锁的并发性

这就牵扯到我前面多次强调的一件事情:

意向锁不会与行级的共享 / 排他锁互斥!!!
意向锁不会与行级的共享 / 排他锁互斥!!!
意向锁不会与行级的共享 / 排他锁互斥!!!

重要的话要加粗说三遍,正因为如此,意向锁并不会影响到多个事务对不同数据行加排他锁时的并发性(不然我们直接用普通的表锁就行了)。
意向锁是如何让表锁和行锁共存的?
有了意向锁之后,前面例子中的事务A在申请行锁(写锁)之前,数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的写锁时就会失败,因为表上有意向排他锁之后事务B申请表的写锁时会被阻塞。

所以,意向锁的作用就是:

为了方便检测表级锁和行级锁之间的冲突,就引入了意向锁。当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他

6 插入意向锁(Insert Intention Locks)

插入意向锁本质上可以看成是一个Gap Lock

普通的Gap Lock 不允许 在 (上一条记录,本记录) 范围内插入数据
插入意向锁Gap Lock 允许 在 (上一条记录,本记录) 范围内插入数据
插入意向锁的作用是为了提高并发插入的性能, 多个事务 同时写入 不同数据 至同一索引范围(区间)内,并不需要等待其他事务完成,不会发生锁等待。

https://www.jianshu.com/p/dca007208a58

7自增锁(Auto-inc Locks)

在InnoDB中,每个含有自增列的表都有一个自增长计数器。当对含有自增长计数器的表进行插入时,首先会执行select max(auto_inc_col) from t for update来得到计数器的值,然后再将这个值加1赋予自增长列。我们将这种方式称之为AUTO_INC Lock。

AUTO_INC Lock是一种特殊的表锁,它在完成对自增长值插入的SQL语句后立即释放,所以性能会比事务完成后释放锁要高。由于是表级别的锁,所以在并发环境下其依然存在性能问题。

从MySQL 5.1.22开始,InnoDB中提供了一种轻量级互斥量的自增长实现机制,同时InnoDB存储引擎提供了一个参数innodb_autoinc_lock_mode来控制自增长的模式,进而提高自增长值插入的性能。innodb_autoinc_lock_mode和插入类型有关,在介绍它之前,我们先来看看都有哪些插入类型

“INSERT-like” statements

泛指所有的插入语句, 它包括 “simple-inserts”, “bulk-inserts”, 和 “mixed-mode inserts”.

“Simple inserts”

插入的记录行数是确定的:比如:insert into values,replace
但是不包括: INSERT … ON DUPLICATE KEY UPDATE.

“Bulk inserts”

插入的记录行数不能马上确定的,比如: INSERT … SELECT, REPLACE … SELECT, and LOAD DATA

“Mixed-mode inserts”

这些都是simple-insert,但是部分auto increment值给定或者不给定. 例子如下(where c1 is an AUTO_INCREMENT column of table t1):

INSERT INTO t1 (c1,c2) VALUES (1,‘a’), (NULL,‘b’), (5,‘c’), (NULL,‘d’);
另外一种 “mixed-mode insert” 就是 INSERT … ON DUPLICATE KEY UPDATE

介绍完插入类型之后,我们再来看看锁模式,即innodb_autoinc_lock_mode

作者:Coding小聪
链接:https://www.jianshu.com/p/dca007208a58
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考

1 https://blog.csdn.net/zcl_love_wx/article/details/82015281
2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL,锁(Locking)用于控制并发访问数据库资源以避免数据一致性问题。MySQL支持多种类型的锁,这些锁可以分为以下几类: 1. **共享锁(Shared Locks, S)**: - 允许读取数据,但阻止其他事务对同一行进行写操作。如果多用户同时请求共享锁,则所有请求都会立即获得锁。 ```sql SELECT * FROM table WHERE id = 1; -- 获取S锁 ``` 2. **排他锁(Exclusive Locks, X)**: - 只允许一个事务独占一行,阻止其他事务进行读取或写入操作。 ```sql INSERT INTO table VALUES (1, 'value'); -- 获取X锁 UPDATE table SET column = 'new_value' WHERE id = 1; -- 获取X锁 DELETE FROM table WHERE id = 1; -- 获取X锁 ``` 3. **意向锁(InnoDB Only, IX)**: - InnoDB存储引擎特有的,用于锁定表级,允许事务锁定整个表以便在其范围内进行插入或删除操作。 ```sql LOCK TABLES table WRITE; -- 获取IX锁 ``` 4. **行级乐观锁(Row-Level Optimistic Locking, ROWX)**: - MySQL的默认行为是行级锁定,但可以通过`SELECT ... FOR UPDATE`语句实现乐观锁,它会检查行的版本号是否与先前读取时一致。 5. **死锁(Deadlocks)**: - 当两个或更多的事务因等待对方释放资源而互相阻塞时,就会发生死锁。 6. **自旋锁(Spin Locks)**: - 这不是MySQL的标准锁机制,而是某些库或优化策略使用的高级概念,它让进程在获取锁失败时循环尝试,直到成功。 了解这些锁的类型有助于管理和优化并发性能,尤其是在高并发环境下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值