- 三种事务bug问题理解
- 脏读:读到其他事务未提交的数据;
- 不可重复读:事务内,相同的where条件,select/update/delete查询结果不一致;
- 幻读:事务内,相同的where条件,insert导致的查询结果不一致;
- 更新丢失:
- mysql的mvcc解决方案
- rc级别-读提交:
- redo.log保证只有事务提交后,修改结果才可见,解决脏读;
- 针对当前读,RC隔离级别保证对读取到的记录加锁 (行锁),存在幻读现象;
- select/update/delete/insert都是当前读,读结果可能不一致,存在不可重复读问题;
- rr级别-可重复读:
- 针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象;
- 针对快照读,普通select并不会加锁,因此select和update读的结果也可能不一致!也存在不可重复读问题;
- Serializable级别 从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)
- 基于锁的并发控制,Lock-Based Concurrency Control
- vs 不可重复读,rc隔离级别已经解决脏读问题,试图解决不可重复读问题;for update 锁定当前读,属于精准匹配锁定,锁定行不可修改,但不能解决幻读问题;
- vs 幻读,rr隔离级别,试图解决幻读问题,for update锁定索引行+gap锁,可以解决幻读问题;
- 理解快照读和当前读
- rr不带锁的查询(select)读快照,rc不带锁读当前;
- (select for update/update/delete)带锁的查询读最新(读当前)
- 理解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
- 最佳实践
- 只要锁多行,就有可能发生死锁,但是只要保证锁定表顺序是一致的就可以避免死锁;
- 顺上,锁定表内有不同行的锁定,也是容易发生死锁的;
- rc+强制读当前+锁,可重复读;
- rr+强制读当前+锁,完全避免幻读;
- 因地制宜;
- 共享锁
- 思考
- rr下,可重复读是指两次select快照读,其他都是读当前,快照读是不准确的,有啥用呢?。
参考:https://www.cnblogs.com/crazylqy/p/7611069.html
网友评论