一、数据库隔离级别
一般来讲,数据库的隔离级别分为读未提交、读已提交(read commit,rc)、可重复读(read reapeat,rr)、串行化四个级别。在mysql中默认隔离级别是rr。读未提交存在脏读问题(A事务读到B事务未提交的数据),读已提交存在重复读问题(A事务读取两次数据a,期间a被B事务修改后提交,两次数据不一致),可重复读存在幻读问题(A事务读取两次a=1的数据,期间B事务插入了一天a=1的数据,导致两次读取结果不一致)。
mysql中通过mvcc解决了脏读和重复读的问题,其中rr是在事务开启时,创建read view。rc在每次查询时创建read view。实际上rc隔离级别上不存在幻读问题,所以可以使用rc+row格式的binlog组合避免幻读。
rr隔离离别下,正常的查询语句其实也不存在幻读问题。但是一些update/delete语句采用的是当前读,这会导致只有行锁的情况下,产生幻读,假设没有间隙锁,当前读中也会出现重复读的问题。mysql在rr隔离级别下解决幻读问题,采用的是行锁+间隙锁,两者合称next-key lock。
我们知道mysql的行锁实际上是加在索引上的,所以进入正题前,我还多聊几句索引与行锁。
二、行锁
在innodb引擎下才有行锁,
行锁是两阶段锁,在事务结束后才会释放。行锁有分为读锁和写锁,两者关系如下图: