本文主要基于《高性能MySQL》
行锁是在InnoDB存储引擎上加的,InnoDB只有在访问行的时候才会加上锁,如果数据能够通过索引过滤掉,那么可以减少加锁的数量。如果索引无法过滤数据,那么InnoDB会检索数据行并返回给服务器层,服务器层再通过where条件过滤,像这种在服务器层才能过滤的数据,InnoDB也会加锁。在早期版本中,返回给服务器层的无效数据行需要等到事务结束才能释放锁,在5.1及以后的版本里面,InnoDB可以在服务器端过滤掉行后就释放锁。
mysql服务器层只能加表锁,比如alter table之类的语句,服务器层加表锁。行级锁只在存储引擎层实现。
1、死锁
死锁出现是因为不同的事务同时争用同一个资源导致的。
mysql提供了死锁检测和死锁超时机制:InnoDB能够检测到死锁的循环依赖,当出现死锁会立即返回一个错误;另一个是查询时间达到锁等待超时的设定后放弃锁请求。
InnoDB处理死锁循环依赖的方式是:将持有最少行级排他锁的事务进行回滚。
2、意向锁
意向锁表示某个事务正在锁定一行或者将要锁定一行,表明一个意图。它分为意向共享锁(IS)和意向排他锁(IX):
- 一个事务对一张表的某行添加共享锁前,必须获得对该表一个IS锁或者优先级更高的锁。
- 一个事务对一张表的某行添加排他锁之前,它必须对该表获取一个IX锁。
意向锁属于表锁,它不与innodb中的行锁冲突,任意两个意向锁之间也不会产生冲突,但是会与表锁(S锁和X锁)产生冲突,如下表:
兼容性 | S锁 | X锁 |
---|---|---|
IS锁 | 兼容 | 冲突 |
IX锁 | 冲突 | 冲突 |
表锁和行锁已经保证了事务的隔离性,确保数据一致,那么为什么还要使用意向锁呢?
意向锁是在当事务加表锁时发挥作用。比如一个事务想要对表加排他锁,如果没有意向锁的话,那么该事务在加锁前需要判断当前表的每一行是否已经加了锁,如果表很大,遍历每行进行判断需要耗费大量的时间。如果使用意向锁的话,那么加表锁前,只需要判断当前表是否有意向锁即可,这样加快了对表锁的处理速度。
意向锁是有存储引擎自己维护的,是内部机制,用户无法操作意向锁。