同时读取和写入同一个元组可能会导致读取逻辑异常,因为写入元组覆盖的非原子动作。
对于 MySql 中的 MVCC,
从概念上讲,由于 ReadView,可以通过可见性规则避免访问正在写入的元组,从而避免发生在同一区域的读取和写入之间的竞争
但是在实现细节上,我还有一个疑问:覆盖一个元组的一个字段会替换堆中的数据。如果有读操作进来,会读写同一个区域,可能会导致读写冲突(字节复制不是原子的)。
如何避免这种读写冲突?是锁吗?
没把我的意思表达的很好,其实是想表达一下锁竞争的问题:</p>
Insert into tableA(age,num) values(1,1) 假设数据库中有一条数据。
此时,在读提交下,以下两个事务同时运行: 事务1:select * from tableA 事务2:更新tableA set age=2
它们在数据库中运行的步骤如下:
- 事务1访问页面中唯一的一条数据:访问该行数据的事务id,通过可见性规则判断数据可见
- 事务2定位到该行数据,发现写入的age字段与当前数据占用的大小相同,于是开始执行替换逻辑
- 事务2将当前数据中age字段的值复制到undo,然后将undo指针指向过去,事务id更新
- 事务 2 将值 2 写回当前数据的年龄字段
- 事务1开始访问age字段,读取到当前数据值为2,访问num字段的值为1,返回(2, 1)
- 事务 2 提交
通过以上步骤的操作,可以看到事务1返回的结果不是预期的,根本原因是读取事务id的动作和写数据的动作(undo、transaction id、new数据)不是互斥的
mvcc 是一种访问设计,但是数据库引擎在访问和写入元组时仍然会竞争同一个区域。Innodb在实现mvcc时如何巧妙避免读写冲突?