锁的种类
- 按照锁的粒度:表锁、页锁、行锁
- 使用方法:共享锁和排他锁
- 思想:乐观锁和悲观锁。
表锁
表锁是粒度最大的锁,开销小,加锁快,不会出现死锁,但是由于粒度太大,因此造成锁的冲突的几率大,并发性能低。
MySQL中的MyISAM存储引擎就支持表锁,MyISAM的表锁模式有两种:表共享读锁和表独占写锁。
页锁
页锁是介于行锁和表锁之间的一种锁,因为页锁是在BDB中支持的一种锁机制。很少人使用。
行锁
行锁是粒度最小的锁机制,行锁的加锁开销大,加锁慢,并且会出现死锁,但是行锁冲突的几率低,并发性能高。
行锁是InnoDB默认支持的锁机制,MyISAM不支持行锁。
共享读锁(S锁)和排它写锁(X锁)
当一个事务对MySQL中的一条数据行加上了S锁,当前事务不能修改该行数据只能执行读操作,其他事务只能对该行数据加S锁不能家X锁。
若一个事务对一行数据加了X锁,该事务能够对该行数据执行读和写操作,其他事务不能对该行数据加任何的锁,既不能读也不能写。
乐观锁和悲观锁
乐观锁和悲观锁在很多框架中都存在的一种思想,不要侠义地认为他们是一种框架的锁机制。
数据库管理系统中为了控制并发,保证在多个事务执行时的数据一致性以及事务的隔离性,使用悲观锁和乐观锁来解决并发场景下的问题。
MySQL中的悲观锁的实现是基于MySQL自身的锁机制实现,而乐观锁需要程序员自己实现的锁机制,最常见的乐观锁实现机制是使用版本号实现。
MyISAM
MyISAM的表级锁可以分为共享读锁和写锁。
如果有一个读请求和写请求同时过来,MyISAM会执行写请求,因为他认为写请求比较重要。
所以MyISAM不适合大量读写的操作。这样会导致长时间读取不到用户数据,用户体验极差。
InnoDB行锁和表锁
InnoDB的行锁也是才用共享读锁(S锁)和排它写锁(X),原理和MyISAM的模式一样。
- 执行非索引条件查询执行的是表锁
- 执行索引查询是否加行锁,还得看MySQL的执行计划,因为针对一些小表查询,可能优化器会直接建议选择全表查询。可以通过explain来查看。
- 用普通键索引的查询,遇到索引值相同的,会启用表锁,该表中其他行也不能进行操作。
InnoDB行锁算法
- Record Lock:单个行记录上的锁
- Gap Lock:间隙锁,锁定一个范围,不包括记录本身
- Next-key lock:record+gap锁定一个范围,包括记录本身。
注意:
- InnoDB对于行的查询使用next-key lock
- Next-key Locking 是为了解决幻读问题。
- 当查询的索引有唯一属性时,将next-key lock降级为record key。
- gap锁的设计目的是为了阻止多个事务将记录插到同一范围,而这会导致幻读问题的产生。
- 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其他情况下只使用record lock)
a.将事务的隔离级别设置为RC提交读
b.将参数innodb_locks_unsafe_for_binlog设置为1。
另外两个表级锁:意向读锁IS和意向写锁IX
意向共享锁(IS):事务打算给数据行加共享锁,事务在给一个数据行加共享锁前必须先给该表加IS锁。
意向排他锁(IX):事务打算给数据行加排他锁,事务在一个数据行加共享锁前必须先给该表加IX锁。
意向锁是一种快速判断表锁与之前可能存在的行锁冲突的机制。
IS和IX是表级锁,不会和行级的X、S锁产生冲突,只会和表级的X、S发生冲突。
范例:向一个表添加表级X锁。
- 加入的是表锁,如果没有意向锁,则需要遍历整个表判断是否有行锁的存在,以免发生冲突。
- 加入的是表锁,如果有意向锁,则只需要判断该意向锁与即将添加的表级锁是否兼容即可,因为意向锁的存在代表了,有行级锁的存在或者即将有行级锁的存在,因而无需遍历整个表,即可获取结果。
- 如果加入的是行锁,需要遍历得到数据行的行锁,然后判断是否兼容。
注:InnoDB存储引擎支持多粒度(granular)锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在。
为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持了一种额外的锁方式,称之为意向锁(Intention Lock)。意向锁是将锁定的对象分为多个层次,意向锁意味这事务希望在更细的粒度上进行加锁。
https://blog.csdn.net/qq_35688140/article/details/102229891
https://blog.csdn.net/qq_43255017/article/details/106818319