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

目录

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.使用合适的隔离级别

相关推荐
Jerry404_NotFound25 分钟前
工厂方法模式
java·开发语言·jvm·工厂方法模式
一起养小猫25 分钟前
【探索实战】Kurator统一流量治理深度实践:基于Istio的跨集群服务网格
java·云原生·istio
微风欲寻竹影27 分钟前
深入理解Java中的String
java·开发语言
Coder_Boy_28 分钟前
基于SpringAI的智能平台基座开发-(二)
java·人工智能·springboot·aiops·langchain4j
lifewange34 分钟前
数据库索引里面的游标是什么?
数据库·oracle
代码or搬砖34 分钟前
TransactionManager 详解、常见问题、解决方法
java·开发语言·spring
廋到被风吹走40 分钟前
【Spring】Spring Context 详细介绍
java·后端·spring
Kiyra1 小时前
LinkedHashMap 源码阅读
java·开发语言·网络·人工智能·安全·阿里云·云计算
PhDTool1 小时前
计算机化系统验证(CSV)的前世今生
数据库·安全·全文检索
sheji34161 小时前
【开题答辩全过程】以 山林湖泊生态文明建设管控系统为例,包含答辩的问题和答案
java·spring boot