行锁在什么时候加锁?MySQL默认加什么锁,加在哪里?
行锁在什么时候加锁?MySQL默认加什么锁,加在哪里?
提示
题眼: 两阶段协议。
行锁在事务需要的时候进行加锁 ,在事务结束的时候再释放锁。什么时候需要是指当进行读操作时进行手动加锁或者是快照读升级为当前读的时候进行加锁。
举个例子:
begin;
select * from book where id = 15;
select * from user where id = 1;
// 以上两个SQL语句是不会加锁的
update book set count = count -1 where id = 15;//给 id 15 这行数据加锁。
update user set count = count +1 where id = 1;
//执行完后,不会把这些锁释放。
commit;
//只有当事务提交后,才会一次性释放所有的锁。这个问题还等价于,MySQL加锁的时机
MySQL默认会加NK锁,也就是行锁+间隙锁,而且锁一般是直接加载索引上的,使用主键索引就加主键,使用普通索引就加普通。按照丁琦老师的说法,加锁时还有一些规则。
根据极客时间的《Mysql实战45讲》中的说明,对于加锁的基本规则大致为5个,包含了两个“原则”、两个“优化”和一个“bug”:
1. 原则 1:加锁的基本单位是 next-key lock。希望你还记得,next-key lock 是前开后闭区间
2. 原则 2:查找过程中访问到的对象才会加锁
3. 优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁
4. 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁
5. 一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止
以上内容,了解即可。
重要
参考答案:
MySQL一般再事务需要加锁的时候才开始加锁,比如当我们第一次执行写操作,也就是将快照读升级到当前读的时候,或者我们手动加锁的时候,而不是说事务一启动 就直接加锁。比如,我们再业务场景中一个事务要执行好几个SQL语句,但是前几个都是select的读操作,那么这个时候事务时不会加锁的。只有执行写入操作,比如insert 或者update的时候,会给对应的数据加上锁。如果我们一开始的select就是for update的话,那直接就会加上锁了。然后,锁的释放不是这个SQL语句执行完就解锁的,而是整个事务执行完,会把事务期间加的所有锁,一次性都释放掉。如果事务很长的话,可能会出现一开始加的锁,会持续很久,影响其他事务的操作,所以一般情况下,我们都要求事务尽可能小一些。
MySQL默认加锁加的是NK锁,也就是行锁+间隙锁,锁会加在索引上。然后的话,MySQL对加锁也有一些优化,比如对唯一索引而言,因为不存在新增一个等值的内容,所以一般NK锁会退化成行锁。
