首先我们需要知道的一个大前提是:mysql的锁是由具体的存储引擎实现的,所以像mysql的MyISAM引擎和InnoDB引擎的锁实现机制是有区别的。
1.表级锁
表级锁每次锁定的是一张表
1)优点:实现逻辑简单,开销小;获取锁和释放锁的速度快;由于表级锁一次会将整个表锁定,所以能很好的避免死锁问题。
2)缺点:由于锁粒度最大,因此出现争用被锁定资源的概率也会最高,致使并发度十分低下。
3)表级锁类型:表共享锁、表排他锁、表意向共享锁、表意向排他锁
表意向共享锁(IS):事务在给一个数据行加行共享锁前(lock inshare mode),必须先取得该表的意向共享锁。
表意向排他锁(IX):事务在给一个数据行加行排他锁前(forupdate),必须先取得该表的意向排他锁IX锁。
表锁的兼容性:
表共享锁(S) | 表排他锁(X) | 表意向共享锁(IS) | 表意向排他锁(IX) | |
表共享锁(S) | 兼容 | 冲突 | 兼容 | 冲突 |
表排他锁(X) | 冲突 | 冲突 | 冲突 | 冲突 |
表意向共享(IS) | 兼容 | 冲突 | 兼容 | 兼容 |
表意向排他(IX) | 冲突 | 冲突 | 兼容 | 兼容 |
2.行级锁
行级锁每次锁定的是一行数据
1)优点:锁粒度小,争用率低,并发高。
2)缺点:实现复杂,开销大;加锁慢、容易出现死锁。
3)行级锁类型
记录锁(Record Locks):只锁定索引项本身。
间隙锁(Gap Locks):锁定索引项中的间隔,或者第一条索引项之前的范围,又或者最后一条索引项之后的范围。
临键锁(Next-key Locks):是记录锁与间隙锁的组合,它的封锁范围,既包含索引项,又包含索引项区间。
注意:行锁锁定的是索引项不是返回的结果集中的记录。如下表中有两条记录,事务一结果集为空但任然锁住了id为9的数据,导致事务二锁等待。
表中数据:

事务一查询:

事务二查询:

3.MyISAM引擎中的锁
MyISAM引擎只支持表所,且只支持表共享锁、表排他锁,对MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;对 MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作。在执行查询语句前,会自动给涉及的所有表加读锁,在执行更新操作(update、delete、insert等)前,会自动给涉及的表加写锁。这个过程并不需要用户干预,因此不需要直接用locktable命令给MyISAM表显式加锁。
4.InnoDB引擎中的锁
InnoDB引擎除支持表级锁中表共享锁、表排他锁之外,增加了对行级锁的支持,而在锁定机制的实现过程中为了让行级锁定和表级锁定共存,InnoDB又增加了两个表级锁,即表意向共享锁、表意向排他锁。
InnoDB行锁是通过给索引项加锁来实现的(如果走的是聚集索引则只给聚集索引加锁,如果走的是辅助索引则会给辅助索引和聚集索引都加上锁)。所以,只有通过索引条件检索数据,InnoDB才使用行级锁(不同的事务隔离级别会选择不同的行锁,如记录锁,临键锁等),否则,InnoDB将使用表锁。
即便在条件中使用了索引字段,但具体是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。




