快照读
是通过MVCC方式解决幻读当前读
是通过next-key lock方式解决幻读select * from t_user where age > 20 for update
select * from performance_schema.data_locks\G;来查询该语句加了什么锁
解释
:
- 表里只有一个主键索引, 假设该语句查询到年龄大于 20 岁的用户共有 6 条行记录。此时事务A在主键索引上加了10个next-key(临键锁),锁的范围是(负无穷,正无穷)把整张表锁住了,因此其他事务在对该表进行增、删、改操作的时候都会被阻塞。
- 或者通过explain会发现type类型为ALL,证明全表扫描
注意
如果对age字段建立索引
思索的四个必要条件
互斥、占有且等待、不可强占用、循环等待
。只要系统发生死锁,这些条件必然成立,但是只要破坏任意一个条件就死锁就不会成立。在数据库层面,有两种策略通过「打破循环等待条件」来解除死锁状态:
设置事务等待锁的超时时间。
当一个事务的等待时间超过该值后,就对这个事务进行回滚,于是锁就释放了,另一个事务就可以继续执行了。在 InnoDB 中,参数 innodb_lock_wait_timeout
是用来设置超时时间的,默认值时 50 秒。开启主动死锁检测。
主动死锁检测在发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect
设置为 on,表示开启这个逻辑,默认就开启。回归业务的角度:
来预防死锁,对订单做幂等性校验的目的是为了保证不会出现重复的订单,那我们可以直接将 order_no 字段设置为唯一索引列,利用它的唯一性来保证订单表不会出现重复的订单 update t_student set score = 100 where id = 25;
然后执行 select * from performance_schema.data_locks\G;
这条语句,查看事务 A 此时加了什么锁。X
,说明是 next-key 锁;X, REC_NOT_GAP
,说明是记录锁;X, GAP
,说明是间隙锁;因此,此时事务 A 在主键索引(INDEX_NAME : PRIMARY)上加的是间隙锁,锁范围是(20, 30)。
事务B同上, 在主键索引(INDEX_NAME : PRIMARY)上加的是间隙锁,锁范围是(20, 30)。
事务Ainsert into t_student(id, no, name, age,score) value (25, 'S0025', 'sony', 28, 90);发现此时多了一个插入意向锁
事务B insert into t_student(id, no, name, age,score) value (26, 'S0026', 'ace', 28, 90);发现也有一个插入意向锁
总结:
快照读
当前读
会加锁错误理解:查询到的数据是一样的 但是update会加锁
正确理解:当前读读的是最新的数据, 快照读要看隔离级别,如果是rr隔离级别,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,并不是最新的数据。
文章https://xiaolincoding.com/