mysql事务隔离和锁

  1. 三种事务bug问题理解
  • 脏读:读到其他事务未提交的数据;
  • 不可重复读:事务内,相同的where条件,select/update/delete查询结果不一致;
  • 幻读:事务内,相同的where条件,insert导致的查询结果不一致;
  • 更新丢失:
  1. mysql的mvcc解决方案
  • rc级别-读提交:
    • redo.log保证只有事务提交后,修改结果才可见,解决脏读;
    • 针对当前读,RC隔离级别保证对读取到的记录加锁 (行锁),存在幻读现象;
    • select/update/delete/insert都是当前读,读结果可能不一致,存在不可重复读问题;
  • rr级别-可重复读:
    • 针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象;
    • 针对快照读,普通select并不会加锁,因此select和update读的结果也可能不一致!也存在不可重复读问题;
  • Serializable级别 从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)
  1. 基于锁的并发控制,Lock-Based Concurrency Control
  • vs 不可重复读,rc隔离级别已经解决脏读问题,试图解决不可重复读问题;for update 锁定当前读,属于精准匹配锁定,锁定行不可修改,但不能解决幻读问题;
  • vs 幻读,rr隔离级别,试图解决幻读问题,for update锁定索引行+gap锁,可以解决幻读问题;
  1. 理解快照读和当前读
  • rr不带锁的查询(select)读快照,rc不带锁读当前;
  • (select for update/update/delete)带锁的查询读最新(读当前)
  1. 理解rc和rr的差异
  • rc下的锁,锁定精确匹配行;rr下的锁,锁定索引+gap锁,锁定的范围广且重,有时候这并不一定是想要;
  • rc下的读快照,每次都读最新的ReadView,也就是最新已事务提交的数据,因此不可重复读;rr下的读快照是可重复读,重复第一条select读时生成ReadView,因此可重复读;
  • 思考,虽然可重复读,但是
A1
select * from user where id=1;
-- effect 0 不存在id=1的记录
A2 
update set age=18 where id=1;
B1
update set age=19 where id=1;
-- rr模式下,id=1被锁定,B1被阻塞;rc模式下,不存在匹配行,B1不会被阻塞;
A3 
commit
  1. 最佳实践
  • 只要锁多行,就有可能发生死锁,但是只要保证锁定表顺序是一致的就可以避免死锁;
  • 顺上,锁定表内有不同行的锁定,也是容易发生死锁的;
  • rc+强制读当前+锁,可重复读;
  • rr+强制读当前+锁,完全避免幻读;
  • 因地制宜;
  1. 共享锁
  • 共享锁
  1. 思考
  • rr下,可重复读是指两次select快照读,其他都是读当前,快照读是不准确的,有啥用呢?。

参考:https://www.cnblogs.com/crazylqy/p/7611069.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。