mysql 并没有幻读_既然MySQL中InnoDB使用MVCC,为什么REPEATABLE-READ不能消除幻读?

第一,这个问题取决于我们如何定义“幻象”异常。

一般意义上,“幻象(phantom)”可被定义为:对于相同的区间查询,插入和删除操作使得对相同的区间查询操作返回不同的结果。如果这么定义幻象异常,那么MVCC下的可重复读(RR)是可以避免幻象的。比如,PostgreSQL,在文档中就说,RR级别下可以避免幻读

早期的数据库都是单版本的,这个定义没什么问题。但是,由于多版本的存在,情形就变得复杂了。RR隔离级别在MVCC实现的数据库中,一般会被实现成快照(SNAPSHOT),这就可能会产生另一种异常。由于事务会读到不同的版本,对于相同区间的查询,事务可能会错过某些满足该条件的并发地插入的记录,该事务只有在插入这条记录的事务提交后才能看到这条记录。进而产生的问题就是,事务本应该读到的数据,却没有被读到。

例如,assignments表有四列(eid, pid, workdate, hours)。assignments表示的是给employee(eid)分配project(pid),并记录某个工作日(workdate)的工时(hours)。限制每个工作日工时不超过8小时。

assign表示分配工时的存储过程,假设eid为1的员工已有两个project, 工时分别为4,1。有两个并发的事务T1, T2, 同时执行assign。当T1,T2开始时,对于满足条件eid = 1 and workdate = '2019.7.11' 的元组,拿到的是相同的快照,它们都判定插入一条工时为4的元组不会使当日工时大于8。

这个异常不满足上面对幻读的定义,然而这个事务调度却是不正确的。一些文献把这种异常也称为幻象(write skew style phantom)

MVCC数据库无法避免这种异常。如果要避免这种异常,就必须要提高隔离级别到可串行化。可串行化的实现,在MySQL中是通过对读加锁(Gap Lock);在PG中是使用SSI算法,通过验证连续的RW依赖检测是否事务是否可串行化

第二,MySQL有一个比较特殊的情形,就是它允许覆盖更新这种行为(不遵守first commit win rule),这让它产生了另一种幻像。

如下面的例子,有两个事务,在RR隔离级别下, select是没有幻读的,但select for update却会产生幻读。因为select是读,通过时间戳读快照,事务2读不到事务1的写入。而select for update被认为是写,是可以更新已提交数据的,所以读到的是最新版本,事务2可以读到事务1的写入。PostgreSQL是没有这个现象的。

事务1 事务2

mysql> start transaction; mysql> start transaction;

Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec)

mysql> select * from t;

Empty set (0.00 sec)

mysql> insert into t values(1);

Query OK, 1 row affected (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.01 sec)

// no phantom

mysql> select * from t;

Empty set (0.00 sec)

// phantom

mysql> select * from t for update;

+------+

| c |

+------+

| 1 |

+------+

1 row in set (0.00 sec)

// update committed row

mysql> update t set c=2;

Query OK, 0 rows affected (0.00 sec)

Rows matched: 1 Changed: 0 Warnings: 0

mysql> commit;

Query OK, 0 rows affected (0.01 sec)

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值