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

目录

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

相关推荐
码上一元2 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
计算机-秋大田2 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
PcVue China2 小时前
PcVue + SQL Grid : 释放数据的无限潜力
大数据·服务器·数据库·sql·科技·安全·oracle
魔道不误砍柴功4 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
锐策4 小时前
〔 MySQL 〕数据库基础
数据库·mysql
枫叶_v4 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
wclass-zhengge4 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud
路在脚下@4 小时前
Springboot 的Servlet Web 应用、响应式 Web 应用(Reactive)以及非 Web 应用(None)的特点和适用场景
java·spring boot·servlet
黑马师兄4 小时前
SpringBoot
java·spring