MYSQl的脏读、幻读、不可重复读

MYSQL的多事物产生的问题,脏读,幻读,不可重复读,其中幻读和不可重复读我不是很理解,不可重复读为:事务B读取了两次数据资源,在这两次读取的过程中事务A修改了数据,导致事务B在这两次读取出来的数据不一致。
这种在同一个事务中,前后两次读取的数据不一致的现象就是不可重复读,修改完数据就是读取的数据不一致啊,前一次读id=1的数据然后将id=1的数据修改,第二次再读肯定不一样,我不理解这个不可重复读。幻读:事务B前后两次读取同一个范围的数据,在事务B两次读取的过程中事务A新增了数据,导致事务B后一次读取到前一次查询没有看到的行。幻读和不可重复读有些类似,但是幻读强调的是集合的增减,而不是单条数据的更新。跟不可重复读一样,对一类数据新增或者修改,数据的条数肯定增加这不是对的吗,这不是正常的吗为什么说与问题?

回答来自Calude:
对于不可重复读,需要注意是在同一个事务内进行了两次读取,而两次读取的数据结果不一致。如果是不同事务,数据变化也是正常的。

例如:

事务A 开始

事务A 第一次读取id=1的数据,name=张三

事务B 开始,更新id=1的数据,将name改为李四

事务A 第二次读取id=1的数据,name=李四

事务A结束

在事务A一个过程中,读取同一数据两次发生了变化,这就是不可重复读。

对于幻读,其关键在于一个范围内的数据集发生了变化:

事务A 开始

事务A 第一次查询id在1-5之间的数据,共5条

事务B 插入一条id=6的数据

事务A 第二次查询id在1-5之间的数据,共6条

事务A 结束

同一个范围内,事务B的插入操作导致事务A的两次查询结果集大小发生了变化,这就是幻读。

不可重复读和幻读都违反了事务的隔离性原则,可能读取到脏数据,所以要通过设置合理的隔离级别来避免。

MySQL的脏读、幻读和不可重复读都是数据库中的一些并发问题,会导致数据的不一致性和不可预测性。
拿转账举个例子:
脏读(Dirty Read):脏读指的是一个事务读取了另一个事务未提交的数据。假设有两个用户A和B,A正在进行转账操作,B在读取A的账户余额时,由于A的事务还未提交,B读取到的余额是不准确的。如果A事务最终回滚,那么B读取到的余额就是脏数据。

幻读(Phantom Read):幻读指的是一个事务在读取某个范围的数据时,另一个事务插入了新的符合条件的数据,导致第一个事务再次读取时发现了之前不存在的数据。继续以上面的例子,如果B在读取A的账户余额后,A的事务又插入了一条转账记录,那么B再次读取A的账户余额时,会发现之前不存在的转账记录,导致数据的不一致。

不可重复读(Non-repeatable Read):不可重复读指的是一个事务在读取某个数据后,另一个事务修改了该数据,导致第一个事务再次读取时发现数据发生了变化。继续以上面的例子,如果B在读取A的账户余额后,A的事务修改了账户余额,那么B再次读取A的账户余额时,会发现数据发生了变化,导致数据的不一致。

为了解决这些问题,可以使用事务隔离级别来控制并发操作的行为,MySQL提供了多个事务隔离级别,如读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable),可以根据具体的需求选择合适的隔离级别来解决并发问题。

【以下回答由 GPT 生成】

脏读(Dirty Read): 脏读指的是一个事务在读取另一个事务未提交的数据时读取到了被修改的数据。也就是说,一个事务读取到了另一个事务修改了但尚未提交的数据,导致读取到的数据是不正确的。

幻读(Phantom Read): 幻读指的是在一个事务中,当它读取了一个范围的数据,并在此范围进行操作时,另一个事务在此范围内插入了新的行,导致第一个事务在之后的读取操作中发现了新插入的行。

不可重复读(Non-repeatable Read): 不可重复读指的是在一个事务中,当它读取了某个数据,并在此之后再次读取同样的数据时,发现数据已经被其他事务修改了,导致两次读取的数据不一致。

幻读和不可重复读的区别: - 幻读是针对数据集合的操作,指的是事务B在两次读取同一个范围的数据时,发现在这两次读取间有其他事务插入数据,导致第二次读取到了多余的数据行。 - 不可重复读是针对单个数据的操作,指的是事务B读取数据后,事务A对此数据进行了修改,导致第二次读取到的数据与第一次读取的数据不一致。

为什么幻读和不可重复读是问题: 幻读和不可重复读都会导致事务在读取数据时得到不一致的结果,破坏了事务的隔离性。虽然对于一类数据进行新增或修改,数据的条数确实会增加,但是幻读和不可重复读所关注的是事务在读取数据的一致性,而不仅仅是数据的条数增减。因此,对于事务的正确性和预期结果来说,幻读和不可重复读都是问题。

下面是在MySQL中如何解决脏读、幻读和不可重复读的问题:

解决脏读(Dirty Read): MySQL的默认事务隔离级别是可重复读(REPEATABLE READ),不会出现脏读的情况,因为事务只会读取已提交的数据。如果需要更严格的隔离级别,可以使用SERIALIZABLE隔离级别。

解决幻读(Phantom Read): 在MySQL中,解决幻读问题可以使用锁定读(Lock Read)或多版本并发控制(MVCC)来实现。在事务开始时,可以使用SELECT ... FOR UPDATE语句来锁定读取的数据,防止其他事务改变数据。另一种方法是使用MVCC,通过使用事务的版本来实现隔离性。

解决不可重复读(Non-repeatable Read): 不可重复读问题可以通过锁定读(Lock Read)或快照隔离(Snapshot Isolation)来解决。锁定读可以使用SELECT ... FOR UPDATE语句来锁定读取的数据,以防止其他事务修改数据。快照隔离可以使用MySQL的READ COMMITTED隔离级别,该级别下每个查询都会读取提交的数据,而不会读取到其他事务未提交的数据。

以上是解决脏读、幻读和不可重复读问题的一些方法。在实际应用中,根据具体场景和需求选择合适的隔离级别和技术手段来保证数据的一致性和正确性。



【相关推荐】


  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7524368
  • 除此之外, 这篇博客: MySQL与Spring事务管理中的 数据库的事务的隔离性是有级别的,不同的级别具有不同的特性,应该在合适的条件下选择合适的隔离级别,不同的数据库产品支持的隔离级别可能不同,甲骨文支持三种,MySQL数据库支持四种隔离级别,分别是:读未提交,读已提交,可重复读,可串行。不同的隔离级别分别可以避免脏读,不可重复读,幻读的情况。值得一提的是,避免不可重复读和幻读都是进行加锁,不同的是一个是对行进行加锁,避免幻读是对表进行加锁。还有就是锁可以分为共享锁和独占锁,一般来说为了避免事务的更新丢失,读写之间会进行加锁,分为悲观锁与乐观锁,悲观锁就是普通的锁,乐观锁就是不加锁,在更新的时候再去验证是否有被修改,如果被修改则读取的数据为脏数据不能修改。这样在修改比较多的情况下比较适合悲观锁,在读取比较多的情况下就比较适合乐观锁。 部分也许能够解决你的问题。

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^