在并发环境下如何处理脏读,幻读,不可重复读

目录

1.对脏读,幻读,不可重复读的理解

2.数据库事务隔离级别

3.如何避免脏读,幻读,不可重复读

3.1如何避免脏读

3.2对乐观锁的理解

3.3如何避免幻读

3.4如何避免可重复读

3.5总结


1.对脏读,幻读,不可重复读的理解

"脏读"、"幻读"和"不可重复读"是数据库事务隔离级别的问题,它们描述了在并发环境下可能发生的一些问题。让我们逐个来理解这些概念:

  • 脏读(Dirty Read) :脏读指的是一个事务读取了另一个事务未提交的数据。在这种情况下,如果那个事务最终回滚了,那么读取的数据就是无效的,因此,脏读就像读到了"脏数据"一样。

  • 幻读(Phantom Read) :幻读指的是在一个事务中,两次查询同样的条件,但是得到的结果集不同。这是由于另一个事务在两次查询之间插入(或删除)了数据,导致第二次查询看到的数据比第一次查询多(或少)。幻读通常发生在并发的插入和删除操作中。

例如,事务A在查询某个范围的数据时,事务B插入了符合该范围的新数据,导致事务A的两次查询返回的结果集合不一致,就发生了幻读。

  • 不可重复读(Non-Repeatable Read) :不可重复读指的是在一个事务中,两次查询同样的数据,但是得到了不同的结果。这是由于在两次查询之间,另一个事务修改或删除了数据,导致第二次查询看到的数据和第一次查询不一样。就像是时间一样,第二次看表的时候,不可能得到第一次看表的时间。

2.数据库事务隔离级别

这些问题的出现是由于数据库事务隔离级别不同导致的。数据库系统提供了不同的隔离级别,每个隔离级别决定了事务在并发执行时,是否能够看到其他事务未提交的数据,以及是否能够避免幻读和不可重复读的问题。

  • READ UNCOMMITTED:最低的隔离级别,允许脏读、幻读和不可重复读。
  • READ COMMITTED :允许不可重复读和幻读,但是避免了脏读。读已经提交了的
  • REPEATABLE READ :避免了脏读和不可重复读,但是允许幻读。可重复读取
  • SERIALIZABLE:最高的隔离级别,避免了脏读、不可重复读和幻读,但是性能较差,因为它会对所有的查询加锁。

3.如何避免脏读,幻读,不可重复读

3.1如何避免脏读

  1. 数据库隔离级别:读已提交
  2. 保证事务的原子性:要么一起成功,要么一起失败
  3. 使用乐观锁:在一些场景下,可以使用乐观锁的方式来避免脏读。乐观锁是通过版本号或时间戳等方式来实现的,当一个事务要更新某行数据时,它会先检查这行数据的版本号或时间戳是否与自己持有的一致,如果一致,则可以更新,否则说明已经被其他事务修改过。
  4. 使用数据库的悲观锁:悲观锁是数据库系统提供的锁机制,可以在读取数据时加锁,阻止其他事务对相同数据的修改,从而避免脏读。
  5. 合理设计事务边界:将事务的范围控制在最小范围内。不要在一个事务中包含不必要的读操作,以减少事务持有锁的时间,从而减少其他事务被阻塞的可能性。
  6. 避免长事务:长时间持有事务会导致锁定资源,增加其他事务被阻塞的可能性。因此,应该尽量避免长事务的存在。

3.2对乐观锁的理解

乐观锁是一种基于数据版本控制的并发控制机制。与悲观锁(在读取数据时就会对数据加锁)不同,乐观锁是在数据更新时才会对数据进行加锁。乐观锁的核心思想是,假设在事务开始时,不会有其他事务来修改数据,因此在事务提交时,会检查在此期间数据是否被其他事务修改。如果没有被修改,则提交成功;如果被修改了,则需要处理冲突。

如果更新操作失败(即版本号或时间戳不一致),需要根据具体情况决定如何处理冲突。常见的处理方式包括回滚事务、重新读取数据并合并、提示用户解决冲突等。 最终目的就是为了保证数据的一致性。

3.3如何避免幻读

  1. 使用SERIALIZABLE隔离级别SERIALIZABLE隔离级别是数据库中最高的隔离级别,它能够避免脏读、不可重复读和幻读。但是,这种隔离级别会对性能产生较大的影响,因为它会对所有的查询加锁,通常需要谨慎使用。

  2. 使用乐观锁

  3. 使用悲观锁 :悲观锁是一种在读取数据时就加锁的机制,可以避免其他事务对相同数据的修改。在关键查询中使用FOR UPDATE(对于MySQL等数据库)或者SELECT ... FOR UPDATE(对于Oracle等数据库)语句,将数据加上排它锁,确保其他事务无法修改这些数据。

  4. 使用范围锁 :范围锁是指在一个范围内对数据进行加锁。例如,对于某个表的某个范围的数据进行查询和更新时,可以使用范围锁确保在这个范围内的数据不会被其他事务修改。

  5. 使用快照隔离(Snapshot Isolation) :快照隔离是一种在事务开始时创建数据的快照,并在事务中使用该快照来保证读取的一致性。这样可以避免不可重复读和幻读的问题。

3.4如何避免可重复读

  1. 事务的原子性
  2. 使用乐观锁
  3. 使用悲观锁:在读的时候上锁
  4. 尽量减少事务的持有时间:长时间持有事务会导致锁定资源,增加其他事务被阻塞的可能性。因此,应该尽量减少事务的持有时间,只在必要的时候才开启事务。

3.5总结

综上所述,避免脏读,幻读和不可重复读,需要做到

1.加乐观锁

2.加悲观锁

3.尽量减少事务的持有时间

4.合理设计事务边界

5.避免长事务

6.保证事务的原子性

7.使用合适的隔离级别

相关推荐
杨云龙UP5 分钟前
Oracle Recycle Bin 回收站详解:DROP TABLE 后还能找回吗?
linux·运维·数据库·sql·mysql·oracle
小马爱打代码17 分钟前
Spring源码 第九篇:Spring 5 源码深度拆解 - Spring 事件驱动模型
java·后端·spring
未来之窗软件服务35 分钟前
酒店门锁V10SDK接口VB-幽冥大陆(一百26)—东方仙盟
数据库·酒店门锁·仙盟创梦ide·东方仙盟·东方仙盟sdk·东方仙盟幽冥大陆
ForgeAI码匠1 小时前
ForgeAdmin|Spring Boot 3 后台框架的自动配置设计:少写配置,多做组合
java·spring boot·后端
tongluowan0071 小时前
Redisson的参数及工作原理
java·redis·lua·分布式锁
墨_风1 小时前
MyBatis时间区间查询异常排查(达梦数据库)
数据库·mybatis·达梦
仙俊红1 小时前
Integer\int对比,equals()\hashcode面试
java·面试·职场和发展
njsgcs1 小时前
用clip把设计经验变成向量数据库,然后每秒检索可以检查3维模型设计的错误吗
数据库
WiChP2 小时前
【V0.1B10】从零开始的2D游戏引擎开发之路
java·数据库·游戏引擎
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【60】检查点机制原理与全流程剖析
java·人工智能·spring