6. 事务如何彼此隔离@I
introduction
事务的另一个巨大特性, 同时也是另一个玄学高发地带, 事务的隔离性, 怎么上的锁, 以及怎么做到彼此隔离的.
uncommitted-read: 你还没提交, 别人就能看到了
committed-read: 你提交了以后别人才能看到
repeatable-read: (在上一条的基础上) 事务的执行过程中读到的数据永远相同
serializable: 读写锁
以上四者能非常好的向我们演示出 : 如果事务的本体就是执行一大堆SQL语句, 那么我直接执行这些语句, 跟我用事务去完成, 能产生什么样的不同. 如果能解释清楚这个问题, 我们就能彻底解构事务玄学:
事务的结果是一体化的, 一定会落盘或者一定会回滚, 任何情况下都会保证这二者之一. 因此如果我们使用事务, 就至少能获得一个一体化的效果.
而事务的另一特性隔离/上锁性, 你可以选择, 要几分熟? 或者直接不要, 就对应着事务的四个等级.
未提交读
如果你选择不要隔离性, 就对应着事务的"读未提交", 这种情况下我们不会使用任何特别的技巧, 除了一体化以外执行事务跟执行一堆SQL语句没有任何的不同:
对于事务里的每一条要执行的语句, 跟直接执行update一样, 我们直接改buffer pool, 并生成一条状态为prepared的redo-log, 后续通过fsync将它落盘, 并把状态修改成committed, 非常原始. 事务在这种等级下仅仅保留了一体性: 允许通过undo-log整体回滚
提交读
从这个等级开始, 我们就开始使用视图了, 在提交读登记下, 每一条SQL语句执行之前都会创建一个快照, 获取当前时间点下的数据:
但是, 如果每一条SQL语句都创建出一个当前数据集的快照, 说明5条SQL语句等于5个快照, 这就说明第一个跟最后一个快照可能是不同的, 因此提交读即使有快照, 一次事务前后的两个值也可能是不同的, 因此我们说在提交读的环境下, 别人修改了东西你是能看到的
可重复读
有了上一节的基础, 我们现在知道为什么别的事务看不见你修改的东西(你的id在他的活跃数组里), 自然也知道你修改的东西为什么别的事务看不见了. 这一切仰仗undolog做合适的回退. 但你们读数据的源/改数据的地点都是Buffer Pool.
思考一个问题, 我们用现在的值, 配合undolog查出以前的值, 这个叫做"read-view", 但是, 如果别人插入一个值呢? 对于一个新的条目, 你怎么查以前的值, 也许你会说直接报错说不存在不就得了, OK, 那么select count(*)怎么解决? 你总不能把所有条目全都遍历一遍吧. 这个问题, 就叫幻读问题
[RecordLock] 我们都知道无论任何等级, 如果你尝试更新一列, 就会加锁(有索引加行锁, 没索引加表锁), 来防止两个tx并发写入的脏写问题
[GapLock] 如果你想执行update或者insert 会把整个区段锁上, 这样你就无法再往里面插入了, 自然也就不会出现幻读的问题了
[NextKey] 这个锁结合上面两个锁, 同时防止并发写入, 以及插入新数据导致的幻读问题
Last updated
Was this helpful?