SQL2加锁分析
id主键+RC
id是主键时,此SQL只需要在id=10这条记录上加X锁即可
id唯一索引+RC
若id列是unique列,其上有unique索引。那么SQL需要加两个X锁,一个对应于id unique索引上的id = 10的记录,<br>另一把锁对应于聚簇索引上的[name='d',id=10]的记录<br>
id非唯一索引+RC
若id列上有非唯一索引,那么对应的所有满足SQL查询条件的记录,都会被加锁。<br>同时,这些记录在主键索引上的记录,也会被加锁<br>
id无索引+RC
若id列上没有索引,SQL会走聚簇索引的全扫描进行过滤,由于过滤是由MySQL Server层面进行的。因此每条记录,无论是否满足条件,都会被加上X锁。但是,为了效率考量,MySQL做了优化,对于不满足条件的记录,会在判断后放锁,最终持有的,是满足条件的记录上的锁,但是不满足条件的记录上的加锁/放锁动作不会省略。
id主键+RR
id是主键时,此SQL只需要在id=10这条记录上加X锁即可
id唯一索引+RR
若id列是unique列,其上有unique索引。那么SQL需要加两个X锁,一个对应于id unique索引上的id = 10的记录,<br>另一把锁对应于聚簇索引上的[name='d',id=10]的记录<br>
id非唯一索引+RR<br>
Repeatable Read隔离级别,防止缓读,需要加Gap锁
所谓幻读,就是同一个事务,连续做两次当前读 (例如:select * from t1 where id = 10 for update;),那么这两次当前读返回的是完全相同的记录 (记录数量一致,记录本身也一致),第二次的当前读,不会比第一次返回更多的记录 (幻象)
Gap锁作用:第一次当前读与第二次当前读之间,其他的事务不会插入新的满足条件的记录并提交
主键和唯一索引,都能够保证唯一性。一个等值查询,最多只能返回一条记录,而且新的相同取值的记录,一定不会在新插入进来,因此也就避免了GAP锁的使用<br>
d列上有一个非唯一索引,对应SQL:delete from t1 where id = 10; 首先,通过id索引定位到第一条满足查询条件的记录,加记录上的X锁,加GAP上的GAP锁,然后加主键聚簇索引上的记录X锁,然后返回;然后读取下一条,重复进行。直至进行到第一条不满足条件的记录[11,f],此时,不需要加记录X锁,但是仍旧需要加GAP锁,最后返回结束
id无索引+RR
在Repeatable Read隔离级别下,如果进行全表扫描的当前读,那么会锁上表中的所有记录,同时会锁上聚簇索引内的所有GAP,杜绝所有的并发 更新/删除/插入 操作。当然,也可以通过触发semi-consistent read,来缓解加锁开销与并发影响,但是semi-consistent read本身也会带来其他问题,不建议使用。
Serializable<br>
MySQL/InnoDB中,所谓的读不加锁,并不适用于所有的情况,而是隔离级别相关的。Serializable隔离级别,读不加锁就不再成立,所有的读操作,都是当前读。