文章字数: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会自动创建隐藏的聚集索引。