1、先下结论
①InnoDB中锁包括表锁、行锁。MyISAM引擎与InnoDB引擎最大区别之一就是MyISAM引擎仅支持表级锁,而InnoDB引擎可以支持更小粒度的行级锁。
InnoDB中的行锁有共享锁(读锁)和排它锁(写锁)两种类型。
②InnoDB有三种锁的算法实现行锁,分别为:
1.Record Lock:单个行记录上的锁。
2.Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。
3.Next-Key Lock:1+2,锁定一个范围,并且锁定记录本身。
③加锁的方式:InnoDB行锁是通过给索引上的索引项加锁来实现的,如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,实际效果跟表锁一样。那如何给索引项加锁:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁:
共享锁:select * from tableName where … + lock in share more
排他锁:select * from tableName where … + for update
④InnoDB行锁的特点:
(1)在不通过索引条件查询时,InnoDB会锁定表中的所有记录。
(2)由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
(3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行。
(4)即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的。
⑤那么什么时候使用记录锁,什么时候使用Next-key锁呢?由两方面的因素决定:1.数据库的隔离级别2.索引项的索引类型,例如:
在REPEATABLE READ(可重复读)隔离级别下,
1.如果查询条件能使用上唯一索引或是聚簇索引,或者是一个唯一的查询条件,那么仅加记录锁;
2.如果是一个范围查询,那么就会给这个范围加上 Next-Key锁 (行锁+Gap锁);
3.如果是普通索引,那么加Next-Key锁(InnoDB使用这个锁解决可重复读隔离级别下的幻读问题);
4.如果是非索引,那么使用表锁。
在(READ COMMITTED)读已提交隔离级别下
1.即使是普通索引,也采用Record Lock(记录锁)锁住一行的数据。
⑥行锁的劣势:开销大;加锁慢;会出现死锁
行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强
2、演示表锁
不通过索引条件查询数据:
3、自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁。
通过代码演示可以看出,通过索引条件去更新数据,该索引条件为主键 聚簇索引 的情况下使用的是行锁。
4、显示加锁
共享锁:select * from tableName where … + lock in share more
排他锁:select * from tableName where … + for update