基于锁的并发控制
与多版本的并发控制协议MVCC(Multi-Version Concurrency Control)相对的,基于锁的并发控制,Lock-Based Concurrency Control。
SQL执行计划:主键扫描 ,唯一键扫描 , 范围扫描 , 全表扫描, 前三种属于索引扫描。
读操作分类
快照读
简单的select操作, 不加锁。例如:select * from mtp_order where order_id = 12;
当前读
读取记录的最新版本,返回的记录都会加上锁(S锁或X锁),保证其它事务不会并发修改当前记录,常见的增删改(真实增删改之前有一次读操作以及加锁)都是当前读。
例如:select * from mtp_order where order_id = 12 lock in share mode ; 这里加的S锁
select * from mtp_order where order_id = 12 for update; 这里加的X锁
2PL(二阶段锁)
锁操作分为两个阶段:加锁阶段与解锁阶段,并且保证加锁阶段与解锁阶段不相交。 (可类比于:分布式事务中两阶段提交操作)。
加锁阶段:只加锁,不放锁。
解锁阶段:只放锁,不加锁。
表锁和行锁的区别
表锁是在mysql server层实现的,行锁是在innoDB引擎层实现的。
聚簇索引
innoDB中即primary ID 。
意向锁与GAP锁
针对相同的操作(插入一条未存在记录),允许先加意向X锁,然后再加GAP锁,但不允许先加GAP,然后申请加意向X锁。
加锁的几种情形
下面分析一条删除语句: delete from t1 where id = 10;
-
组合一:id列是主键,RC隔离级别
仅在主键记录上加X锁即可
-
组合二:id列是二级唯一索引,RC隔离级别
先在id索引上加X锁,然后对应于聚簇索引上加X锁。
-
组合三:id列是二级非唯一索引,RC隔离级别
所有满足SQL查询条件的记录,都会被加X锁。同时,这些记录在主键索引上的记录,也会被加X锁。
-
组合四:id列上没有索引,RC隔离级别
全部被加上X锁。既不是加表锁,也不是在满足条件的记录上加行锁。
-
组合五:id列是主键,RR隔离级别
仅在主键记录上加X锁即可
-
组合六:id列是二级唯一索引,RR隔离级别
id唯一索引满足条件的记录上加X锁,同时对应的聚簇索引上的记录加X锁
-
组合七:id列是二级非唯一索引,RR隔离级别
通过id索引定位到第一条满足查询条件的记录,加记录上的X锁,加GAP上的GAP锁,然后加主键聚簇索引上的记录X锁,然后返回;然后读取下一条,重复进行。直至进行到第一条不满足条件的记录,此时,不需要加记录X锁,但是仍旧需要加GAP锁 。
-
组合八:id列上没有索引,RR隔离级别
全表扫描的当前读,那么会锁上表中的所有记录,同时会锁上聚簇索引内的所有GAP,杜绝所有的并发 更新/删除/插入 操作。
-
组合九:Serializable隔离级别
所有的读操作,都是当前读。