众所周知,InnoDB中既有读锁也有写锁,也称为共享锁和排他锁。这两个锁可以加在整个表或行上。MySQL本身提供了锁表的能力:读锁:LOCKTABLEtable_nameREAD使用读锁来锁表,会阻塞其他事务的写操作写锁:LOCKTABLEtable_nameWRITE使用写锁来锁表,会阻塞其他事务的读写操作写操作的行锁由InnoDB存储引擎提供,MySQL本身不提供行级锁的能力:读锁,如SELECT*FROMtable_nameWHERE...LOCKINSHAREMODE加上行级读锁,会阻塞其他事务对行记录的写锁,比如SELECT*FROMtable_nameWHERE...FORUPDATE加上行级写锁,会阻塞其他事务的读写操作在行记录上。有表锁和行锁。让我们考虑一下这两种类型的锁的共存。看下面的例子:事务A加了一个行级读锁,锁住表中的一行,使得该行只能读不能写。之后,事务B尝试对整个表申请写锁。如果事务B申请成功,理论上可以修改表中任意一行,与A持有的行级读锁冲突,如果数据库需要避免这种冲突,需要阻塞B的申请,直到A释放行级读锁。数据库如何判断这种冲突?第一步:判断表是否被其他事务用表级锁锁住第二步:判断表中每一行是否被行级锁锁住看起来不难,但请注意步骤2,判断表中的每一行,大家,怎么判断呢?显然,需要遍历!遍历表中的每一行。小学生可以认为这样的判断方式效率太低了。所以有意向锁!我们先看一下意向锁的解释:意向锁是表级的锁,表示事务稍后对表中的一行需要哪种类型的锁(共享或独占)。下一个事务将使用什么样的锁。意向锁有两种:意向共享锁/读锁(ISLock):当事务想要获取表中某些行的读锁(行级读锁)时,InnoDB存储引擎会自动获取表的意向优先读锁(表级锁)意向排它锁/写锁(IXLock):当一个事务想要获取表中某些行的写锁(行级写锁)??时,InnoDB存储引擎会自动获取表的意向写锁(表级锁)注意这里的自动:申请意向锁的动作是由数据库完成的,即事务A申请某行的行锁时,数据库会先自动开始申请表的意向锁,不需要我们程序员使用代码去申请。在意向锁的情况下,事务A要申请行级读锁,必须先申请表的意向读锁。申请成功后,可以继续申请一条行记录的行级读锁。在有意向锁的情况下,上面的判断可以改成:第一步(不变):判断表是否已经被其他带有表级锁的事务锁住第二步:查找表上的意向读锁(表示有的表中的行被行级读锁锁住了),意向读锁和表级写锁是互斥的,所以事务B对表的写锁申请会被阻塞。也就是说,简化了原来步骤2中遍历表中每一行来判断整张表是否存在表级意向锁的操作,大大提高了效率。这就是有意锁定的原因。
