webliyang 2020-05-27
select ... lock in share mode //共享锁 select ... for update //排他锁
行锁的3种算法:
record lock:单个行记录上的锁
gap lock:锁定范围,不锁定记录本身,只在RR里使用
next-key lock:锁定范围,并锁定记录本身,假如有两个数据3,7,则对区间(-无穷,3],(3,7],(7,正无穷)进行上锁
Previous-Key Lock:和next-key相反,区间左闭右开
innodb对于行的查询使用next-key lock,当查询的索引含有唯一属性时,将next-key lock降级为record key
乐观锁,适合读多写少的情景
MVCC:update table set name = ‘NewValue‘, version = version + 1 where id = #{id} and version = #{version};
CAS:ABA问题,自旋开销大
悲观锁适合频繁写入的情景
快照读:简单的select操作,属于快照读,不加锁。 select * from table where ?;
当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;
所有以上的语句,都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁)。
死锁:指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象
解决死锁:
超时,回滚某一事务,另一事务就能得到执行,缺点是回滚的代价可能很高
wait-for graph(等待图),深度优先算法判断是否存在回路
隔离级别与锁的关系 待验证
在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突
在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;
在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。
SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。
可通过 show engine innodb status 以及 information_schema 库下的innodb_trx、innodb_locks、innodb_lock_waits 观察 lock 的信息。
只有通过索引进行检索时,才会使用行锁,否则使用表级锁