前言
mysql 按锁的范畴分三种
- 表级锁:开销小,加锁快;不会呈现死锁,锁定粒度大,产生锁抵触概率最高,并发度最低。
- 行级锁:开销大,加锁慢,会呈现死锁,锁定粒度小,产生锁抵触的概率最低,并发度最高。
-
页面锁:开销和加锁工夫界于表锁和行锁之间,会呈现死锁,锁定粒度界于表锁和行锁之间,并发度个别。
从上述三种锁的特点来看,很难说哪种锁更好,只能就具体利用的特点来说哪种锁更适合。比方,MyISAM 和 MEMORY 引擎采纳的是表级锁;InnoDB 引擎既反对行级锁,也反对表级锁,但默认状况下采纳行级锁。InnoDB 的加锁模式
InnoDB 实现了以下两种类型的行锁。
- 共享锁(S):容许一个事务读一行,阻止其余事务取得雷同数据的排他锁,也叫读锁。
- 排他锁(X):容许取得排他锁的事务更新数据,阻止其余事务获得雷同数据集的共享锁与排他锁,也叫写锁。
同时 mysql 还反对与行共享锁和行排他锁相似的表共享锁和表排他锁因为锁的粒度不同,表锁的范畴笼罩了行锁的范畴,所以表锁和行锁会产生抵触,例如事务 A 对表中某一行数据加了行锁,而后事务 B 想加表锁,失常来说是应该要抵触的。要判断是否抵触就得遍历每一行数据了,这样的效率不高,因而咱们就有了意向表锁。
意向锁的次要目标是为了使得 行锁 和 表锁 共存,事务在申请行锁前,必须先申请表的意向锁,胜利后再申请行锁。
意向锁分为动向共享锁和动向排他锁。
- 动向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁之前必须先去的该表的动向共享锁
- 动向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先获得该表的动向排他锁。
上述锁模式的兼容状况如下表所示
右侧代表申请锁模式,下侧代表以后锁模式 | X | IX | S | IS |
---|---|---|---|---|
X | 抵触 | 抵触 | 抵触 | 抵触 |
IX | 抵触 | 兼容 | 抵触 | 兼容 |
S | 抵触 | 抵触 | 兼容 | 兼容 |
IS | 抵触 | 兼容 | 兼容 | 兼容 |
如果一个事务申请的锁模式与以后的锁模式兼容,InnoDB 就将申请的锁授予该事务,反之,如果两者不兼容,该事务就要期待锁开释。
意向锁是表级锁,然而却示意事务正在读或写某一行记录,而不是整个表,所以意向锁之间不会产生抵触,真正的抵触在加行锁时查看。
加锁办法
意向锁是 InnoDB 主动加的,不须要用户干涉。
隐式上锁
- 对于 UPDATE,DELETE 和 INSERT 语句,InnoDB 会主动给设计数据集加排他锁;
- 对于一般 SELETE 语句,INNODB 不会加任何锁;
-
InnoDB 会依据隔离级别在须要的时候主动加锁;
显式上锁
select * from tableName lock in share mode;// 读锁 select * from tableName for update;// 写锁
解锁
- 提交事务(commit)
- 回滚事务(rollback)
-
kill 阻塞过程
上读锁实例事务 A 事务 B begin; select * from teacher where id = 2 lock in share mode;// 上读锁 select * from teacher where id = 2;// 能够失常读取 update teacher set name = 3 where id =2;// 能够更新操作 update teacher set name = 5 where id =2;// 被阻塞 commit; update teacher set name = 5 where id =2;// 更新操作胜利 上写锁实例
事务 A 事务 B begin; select * from teacher where id = 2 for update;// 上写锁 select * from teacher where id = 2;// 能够失常读取 update teacher set name = 3 where id =2;// 能够更新操作 update teacher set name = 5 where id =2;// 被阻塞 rollback; update teacher set name = 5 where id =2;// 更新操作胜利 为什么上了写锁,别的事务还能够读操作?
因为 InnoDB 有 MVCC 机制(多版本并发管制),能够应用快照读,而不会被阻塞。InnoDB 行锁实现形式
行锁(Record Lock)
行锁总是会去锁住索引记录,如果 InnoDB 存储引擎表建设的时候没有设置任何一个索引,这时 InnoDB 存储引擎会应用隐式的聚簇索引来进行锁定。
间隙锁(Gap Lock)
当咱们用范畴条件而不是相等条件检索数据,并申请共享或排他锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁;对于键值在条件范畴内但并不存在的记录,叫做“间隙(GAP)”,InnoDB 也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key 锁)。
长处:解决了事务并发的幻读问题
有余:因为 query 执行过程中通过范畴查找的话,他会锁定争个范畴内所有的索引键值,即便这个键值并不存在。
间隙锁有一个致命的弱点,就是当锁定一个范畴键值之后,即便某些不存在的键值也会被无辜的锁定,而造成锁定的时候无奈插入锁定键值范畴内任何数据。在某些场景下这可能会对性能造成很大的危害。Next-key Lock 锁
同时锁住数据 + 间隙锁
在 Repeatable Read 隔离级别下,Next-key Lock 是默认的行记录锁定算法。
如果 teacher 表中只有 101 条记录,其 id 值别离是 1 -101,SQL 语句如下Select * from teacher where id 〉 100 for update;
这是一个范畴条件检索,InnoDB 不仅会对符合条件的 id 值为 101 的记录加锁,也会对 id 大于 101(不存在的记录)的“间隙”加锁。
乐观锁与乐观锁
- 乐观锁 (Optimistic Lock):假如不会产生并发抵触,只在提交操作时查看是否违反数据完整性。乐观锁不能解决脏读的问题。
乐观锁, 顾名思义,就是很乐观,每次去拿数据的时候都认为他人不会批改,所以不会上锁,然而在更新的时候会判断一下在此期间他人有没有去更新这个数据,能够应用版本号等机制。乐观锁实用于多读的利用类型,这样能够进步吞吐量,像数据库如果提供相似于 write_condition 机制的其实都是提供的乐观锁。 -
乐观锁 (Pessimistic Lock):假设会产生并发抵触,屏蔽所有可能违反数据完整性的操作。
乐观锁,就是很乐观,每次去拿数据的时候都认为他人会批改,所以每次在拿数据的时候都会上锁,这样他人想拿这个数据就会被阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比方行锁,表锁等,都是在做操作之前先上锁。总结
锁和多版本数据(MVCC)是 InnoDB 实现一致性读和四种隔离隔离级别的伎俩。
因而,在不同的隔离级别下,InnoDB 解决 SQL 时须要的锁是不同的。