数据库中的锁
- 如果按照锁的粒度来分的话,分为表锁和行锁;如果按照读写功能来分的话,分为读锁和写锁。
表锁
- 特点: 即使操作一条记录也会锁住整个表,锁定粒度较大,发生锁冲突的概率高,并发度最低。但开销小,加锁快,而且不会出现死锁。
- 表锁是mysql中开销最小的策略,它会锁定整张表,用户在对表进行写操作前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。
行锁
- 特点: 操作时只锁某些行,不对其它行有影响,锁粒度较小,发生锁冲突的概率低,并发度高。但开销大,加锁慢,而且会出现死锁。
- 行锁可以最大程度的支持并发处理,同时也带来了最大的锁开销,InnoDB存储引擎实现了两种行锁:共享锁和排他锁。
InnoDB 的行锁是怎么实现的?
-
InnoDB 行锁是通过索引上的索引项来实现的。意味着:只有通过索引条件检索数据,InnoDB 才会使用行级锁,否则,InnoDB将使用表锁!
-
对于主键索引:直接锁住主键索引即可。
-
对于普通索引:先锁住普通索引,接着锁住主键索引,这是因为一张表的索引可能存在多个,通过主键索引才能确保锁是唯一的,不然如果同时有2个事务对同1条数据的不同索引分别加锁,那就可能存在2个事务同时操作一条数据了。
共享锁和排他锁
- mysql的锁机制分为表级锁和行级锁,共享锁和排他锁都属于行级锁。
- 共享锁又称为读锁,简称S锁,指多个事务对同一数据可以共享一把锁,他们都能访问到这个数据,但只能读不能改。
- 排他锁又称为写锁,简称X锁,它不能与其他锁并存,如果一个事务获取了一个数据行的排他锁,那其他事务就不能再获取该行的其他锁了,包括共享锁和排他锁。而获取了这个排他锁的事务可以对数据行进行读和写。
- 常见的几种 SQL 语句的加锁情况如下:
select * from table:不加锁
update/insert/delete:排他锁
select * from table where id = 1 for update:id为索引,加排他锁
select * from table where id = 1 lock in share mode:id为索引,加共享锁
意向锁
- 意向锁是一种表级锁,如果事务想要给表中几行数据加上行级共享锁,那么需要先在表级别加上意向共享锁(IS);如果事务想要给表中几行数据加上行级排他锁,那么需要先在表级别加上意向排他锁(IX)。
- 目的/作用:当向一个表添加表级排他锁或表级共享锁时,如果没有意向锁的存在,则需要遍历整个表来判断是否存在不兼容的行锁,以免发生冲突。如果有了意向锁,只需要判断该意向锁与想添加的表级锁是否兼容即可,因为意向锁的存在代表了有行级锁的存在,所以无需遍历整个表就可以获取结果,减少了整个检查过程,将检查每一行的排他锁变成只检查一个意向锁。
间隙锁
- 间隙锁指的是锁定一个范围内的索引记录,开区间,不包括双端端点,对于键值在条件范围内但不存在的记录,叫做间隙,间隙锁也会对这个间隙加锁。
- 目的/作用:让其他事务无法在间隙中新增数据,从而防止了幻读。
- 在可重复读的隔离级别下才能生效。