表锁:
行锁:
InnoDB和MyISAM最大的不同有两点:
- InnoDB支持事务(TRANSACTION)
- InnoDB支持行锁
MyISAM在执行查询SELECT前,会自动给涉及的所有表加读锁,在执行update、insert、delete操作会自动给涉及的表加写锁。
InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行锁。
读锁只会堵塞写,不会堵塞读,但是写锁会堵塞读和写
幻读例子:
客户端A查询后,客户段B插入一条数据Q,客户段A想插入Q却报主键冲突,但是查询不出来数据Q;但是可以对Q进行更新。
串行化
把所有读到的数据加锁。
效率很低,很少用。
间隙锁
一个值落到一个范围,这个范围的所有数据都会被加锁
如图:间隙就有id为(3,10)、(10,20)、(20,正无穷)
update account set name = ‘zhuge’ where id >8 and id <18
则其他事务没法在这个范围所包含的所有行记录(包括间隙记录)以及行记录所在的间隙里插入或修改任何数据。即id在(3,20]区间都无法修改数据,20也包含在内。
间隙锁是在可重复度隔离级别下才会生效
临键锁(Next-key-Locks)
临键锁是行锁和间隙锁的组合,想上面的例子中(3,20]的整个区间可以叫临键锁。
无索引行会升级为表锁
InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级到表锁
锁主要是加在索引上,如果对非索引字段更新,行锁可能会变成表锁。
优化建议
- 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁;
- 合理设计表索引,尽量缩小锁的范围
- 尽可能减少检索条件范围,避免间隙锁
- 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的SQL尽量放在事务最后执行;
- 尽可能低级别事务隔离
https://note.youdao.com/ynoteshare/index.html?id=354ae85f3519bac0581919a458278a59&type=note&_time=1701862479906