19、MySQL进阶:并发事务问题及解决方案

文章目录

  • 生猛干货
  • Pre
  • 脏读
  • 不可重复读
  • 幻读
  • Solutions
  • 搞定MySQL

*


生猛干货

带你搞定MySQL实战,轻松对应海量业务处理及高并发需求,从容应对大场面试


Pre

MySQL - 多版本控制 MVCC 机制初探

中我们初步了解了 MVCC 的原理及其实现。 随着数据库并发事务处理能力的增强,数据库资源的利用率也会大大提高,从而提高了数据库系统的事务吞吐量,可以支持更多的用户并发访问。

但并发事务处理也会带来一些问题,如:脏读、不可重复读、幻读等等


脏读

一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫作"脏读"(Dirty Reads)。

简答来说,读取了其他事务未提交的数据


不可重复读

一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫作“ 不可重复读”(Non-Repeatable Reads)。


幻读

一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”(Phantom Reads)。


Solutions

MySQL 数据库是通过事务隔离级别来解决上述问题的。

*

我们举例说明“脏读”和“不可重复读”的问题

【RC 隔离级别】
MySQL 中默认的事务隔离级别是 RR,这里设置成 RC 隔离级别,此时提交事务 B 修改 id=1 的数据之后,事务 A 进行同样的查询操作,后一次和前一次的查询结果不一样,这就是不可重复读(重新读取产生的结果不一样了)。这里事务 A 读到了事务 B 提交的数据,即是“脏读”。

*


【RR隔离级别】

下面我们来看看在mysql默认的RR隔离级别下的情况。当 teacher_id=1时,事务 A 先进行一次读取操作,事务 B 中间修改了 id=1 的数据并提交,事务 C 也插入了一条数据并提交。事务 A 第二次读到的数据和第一次完全相同。所以说它是可重读的。

*


【幻读】

行锁可以防止不同事务版本的数据在修改提交时造成数据冲突的情况。但如何避免别的事务插入数据造成的问题呢。我们先来看看在 RC 隔离级别下的处理过程。

如下图所示,事务 A 修改了所有 teacher_id=30 的数据,但是当事务 B INSERT 新数据后,事务 A 发现莫名其妙的多了一行 teacher_id=30 的数据, 而且没有被之前的 UPDATE语句所修改,这就是“当前读”的幻读问题。

*
跟上面的例子一样,也是在 RC 事务隔离级别下,这时事务 B INSERT 了一条数据,并提交,而事务 A 读到了事务 B 新插入的数据。这也是幻读,如下图所示。

*

这里就需要重点注意不可重复读和幻读的区别了。前面讲了它们的含义,这个提醒大家的是:不可重复读重点在于 UPDATA 和 DELETE,而幻读的重点在于 INSERT。它们之间最大的区别是如何通过锁机制来解决它们产生的问题。这里说的锁只是使用悲观锁机制。

那么在RR 隔离级别下,事务 A 在 UPDATE 后加锁,事务 B 无法插入新数据,这样事务 A在 UPDATE 前后读的数据保持一致,避免了幻读。

跟上面的案例一样,也是在 RR 事务隔离级别下,事务 A 在 UPDATE 后加锁,对于其他两个事务,事务 B 和事务 C 的 INSERT 操作,就必须等事务 A 提交后,才能继续执行。这里就用到了“锁”,这里使用的是 Gap 锁,后面会详细讲解。它和上面的情况一样,解决了“幻读”的发生,如下图所示。

*


搞定MySQL

*

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: