目录
1. MySQL
锁的分类
- 按锁的粒度划分,可分为表级锁、行级锁
- 按锁级别划分,可分为共享锁、排他锁
- 按使用方式划分,可分为乐观锁、悲观锁
1.1. 表级锁与行级锁
1.1.1. 表级锁
表锁锁住的是一整张表,是开销最小的锁策略。表锁虽然开销小,锁表快,但高并发下性能低,发生锁冲突的概率最高
1.1.2. 行级锁
行级锁锁住的是表中的一行数据,行锁是开销最大的锁策略。行锁虽然开销大,锁表慢,但高并发下相比之下性能更高,发生锁冲突的概率最低
行级锁都是基于索引的,如果一条 SQL
语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住。如果有索引,并且查询条件中也带有这些字段,那么就会使用行级锁
行级锁并不是锁记录,而是锁索引
- 如果一条
SQL
语句用到了主键索引,MySQL
会锁住主键索引 - 如果一条语句操作了非主键索引,
MySQL
会先锁住非主键索引,再锁定主键索引
对于为什么行级锁并不是锁记录,而是锁索引。可以参考 MySQL 的索引中的索引实现
需要注意:当你需要更新一张较大表的大部分甚至全表的数据时。而你又傻乎乎地用索引作为检索条件。一不小心开启了行锁(没毛病啊!保证数据的一致性!)。可 MySQL
却认为大量对一张表使用行锁,会导致事务执行效率低,从而可能造成其他事务长时间锁等待和更多的锁冲突问题,性能严重下降。所以 MySQL
会将行锁升级为表锁,即实际上并没有使用索引。我们仔细想想也能理解,既然整张表的大部分数据都要更新数据,在一行一行地加锁效率则更低
1.2. 共享锁(读锁)与排他锁(写锁)
1.2.1. 共享锁(读锁)
共享锁:一个事务获取了共享锁,其它事务也可以获取共享锁进行读操作,但其它事务不能获取排他锁,也不允许任何线程对该行数据进行修改
SELECT ... LOCK IN SHARE MODE;
1.2.2. 排它锁(写锁)
排他锁:如果事务 T
对数据 A
加上排它锁后,则其它事务不能再对 A
加任何类型的锁。得到排它锁的事务既能读数据,又能修改数据
SELECT ... FOR UPDATE