文章字数:1042,阅读全文大约需要4分钟
锁分类
按照粒度可以分为表级锁table-level locking
和行级锁row-level locking
表级锁:开销小,加锁快。但是因为锁定的粒度大,发生冲突的概率高,支持并发度低。适合查询为主的应用
行级锁:开销大,加锁慢。但是粒度小,发生冲突概率低,支持并发高。
InnoDB
默认采用行级锁MyISAM
和MEMORY
默认采用表级锁
行锁
InnoDB
实现类两种类型的行锁
共享锁
S
:获取该锁的事务可以读取数据,并同时允许其他事务获取改行的共享锁,但阻止其他事务获取排他锁。排他锁
X
:获取该锁的事务可以更新或删除数据行,同时阻止其他事务获取该行的共享锁和排他锁。
锁类型 | 共享锁S | 排他锁X |
---|---|---|
共享锁S | 兼容 | 冲突 |
排他锁X | 冲突 | 冲突 |
手动添加行锁
默认情况下锁都是自动获取的,但也可以手动加锁。
select * from table where id = 1 for share
for share就是加共享锁,MySQL8.0
之前的版本可以使用select...lock in share mode
由于 InnoDB 中的自动提交 autocommit 默认设置为 ON,我们必须在事务中为数据行加锁;或者将 autocommit 设置为 OFF。select * from table where id = 1 for update
for update是获取排他锁
数据行被其它事务加了共享锁,并且事务未结束(即未释放)此时其它事务加排他锁则会处于等待状态,直到超时。(因为不兼容)
意向锁
为了兼容表级锁和行级锁,InnoDB
采用了意向锁(属于表级锁)。意向锁为自动添加,也可以手动LOCK TABLE
添加
- 意向共享锁(IS):事务在给数据行加行级共享锁之前,必须先取得该表的 IS 锁。
- 意向排他锁(IX):事务在给数据行加行级排他锁之前,必须先取得该表的 IX 锁。
锁类型 | 共享锁S | 排他锁X | 意向共享锁IS | 意向排他锁 |
---|---|---|---|---|
共享锁S | 兼容 | 冲突 | 兼容 | 冲突 |
排他锁X | 冲突 | 冲突 | 冲突 | 冲突 |
意向共享锁IS | 兼容 | 冲突 | 兼容 | 兼容 |
意向排他锁IX | 冲突 | 冲突 | 兼容 | 兼容 |
意向锁只是标记当前有事务在操作行级锁,意向锁和意向锁之间并不会冲突
手动添加意向锁
select * from t where id = 1 for update
添加行锁会自动添加表锁lock tables t read
也可以手动添加unlock tables
释放表上的排他锁
行锁实现
记录锁
Record Lock
:通过索引值进行加锁间隙锁
Gap Lock
:BETWEEN 1 and 10
这样的语句会产生多行记录的锁,此时就是间隙锁。代表一段区域,可以是两个索引之间、某个索引之前、某个索引之后。Next-key
锁:该锁可以锁住当前位置和之前的区域,即记录锁+间隙锁。主要用于解决幻读,使用for update
时通过加Next-key
解决幻读。普通情况下采用MVCC
解决幻读
可以使用SHOW ENGINE INNODB STATUS
命令查看InnoDB
监控中关于锁的事务数据
记录锁永远都是锁定索引记录,优先聚集索引,没有定义索引InnoDB
会自动创建隐藏的聚集索引。