InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MYSQL与Oracle不同,后者通过在数据块中对应数据行加锁来实现的。InnoDB这中行锁实现特点意味着:只有通过索引条件检索数据,InnoDB使用行级锁,否则,InnoDB使用表锁!
1. 行锁的实现方式
- InnoDB 行锁:行锁是加在索引上的索引项(index entry)上,而不是直接加在具体的数据行上。换句话说,InnoDB 在访问某行数据时,如果是通过索引来定位这行数据,行锁会加在索引项上。
- Oracle 行锁:Oracle 是通过在数据块中的实际数据行上直接加锁。也就是说,Oracle 的锁机制是锁住具体的数据存储位置。
2. 行锁的作用条件
InnoDB 的行锁机制意味着:
- 通过索引访问:如果你通过索引(例如主键索引或普通索引)条件去查询某行数据,InnoDB 会对该索引项(或对应范围)加锁,这样只锁住必要的行,其他行可以并发操作。
- 非索引访问:如果你通过非索引字段进行查询,InnoDB 由于没有明确的索引项可以锁定,无法精确地加行锁,因而可能会回退使用表锁,锁住整个表以保证一致性。
3. 理解关键点
-
索引与行锁的关系:InnoDB 通过锁定索引项而非物理数据行,从而实现更细粒度的并发控制,这样多个事务可以对不同的行进行并发操作,只要这些行不共享相同的索引项。行锁的粒度可以是单个索引项或索引项的范围。
-
锁定方式依赖于查询条件:如果查询中使用了索引(如通过
WHERE
子句条件访问),锁只会加在满足条件的索引项上,从而实现行级锁;如果没有使用索引(如全表扫描),InnoDB 为了避免并发问题,会选择锁住整个表,即使用表级锁。
4. 举例说明
-
通过索引查询(行锁):
-
SELECT * FROM student WHERE id = 5 FOR UPDATE;
在这个查询中,
id
是表student
的主键索引,InnoDB 会在主键索引项上加锁,从而只锁定id = 5
的这一行。 -
未通过索引查询(可能的表锁):
-
SELECT * FROM student WHERE age = 20 FOR UPDATE;
假设
age
列没有索引,InnoDB 需要扫描整个表来查找满足条件的行。在这种情况下,InnoDB 可能选择加表锁来避免其他事务对表的并发修改。
总结
InnoDB 的行锁是基于索引项加锁的,而不是直接锁定物理数据行。这种设计可以提高并发性能,因为它只锁定查询涉及的行,而不会锁定不相关的行。但前提是查询必须基于索引,否则会回退到表锁,影响并发性能。因此,在设计数据库表时,合理使用索引是非常重要的,可以帮助 InnoDB 更有效地实现行级锁。