mysql锁相关
优秀博客:https://www.zhihu.com/column/c_1104074839660294144
mysql锁是为了解决数据的一致性,但是过多加锁会造成阻塞,降低并发性能;基于此innodb存储引擎使用了mvcc(多版本控制)的方式减少加锁。
mvcc只针对rc、rr的隔离级别生效,并且rc隔离级别下读取的是最新的数据(即读取到的数据为最新一份快照数据),rr隔离级别下读取的是(当前事务开始时的快照数据)
mysql默认情况下快照读使用mvcc的模式,不加锁。
当前读时会对数据加锁,可以显示地加共享锁或者排他锁
所有的更新操作(增删改)都会加锁
锁和隔离性(下面的结论前提为隔离级别为RR的级别下):
快照读情况下:不存在幻读(连续两次读到的数据不同),mvcc来解决
当前读情况下:不存在幻读,next-key lock来解决,next-key lock除了给当前的索引范围(也可能为单条记录)加锁外,还会对两条记录的间隙加锁(辅助索引的情况)
但是注意一个问题,下面的情形可能导致数据更新丢失:
事务1读数据,存入内存
事务2读数据,存入内存
事务1根据内存值更新数据并提交
事务2根据内存值更新数据并提交
这样会造成事务1的更新丢失,解决方案:使用当前读的方式将记录加锁,让整个流程串行化
mysql默认使用next-key lock的方式加锁,如果是唯一索引则会值使用行锁。
死锁的两种形式:
1、事务循环依赖锁
2、一个事务的成功会造成另一个事务向后获取锁,此时mysql会主动死锁(也类似循环依赖)
第二种情况case:假设数据库中已经有记录 1 2 4 (id为唯一索引)
T1 T2
select * from t where id = 4 for update
select * from t where id <= 4 lock in share mode; 阻塞,由于id=4的记录被事务一上了排他锁,但是此时T2已经获取了id<4记录的锁
insert into t values(3)(死锁)