首页 > 编程语言 >Java 面试题:事务隔离级别以及并行事务会出现什么问题&&怎么解决脏读、不可重复读和幻读问题 --xunznux

Java 面试题:事务隔离级别以及并行事务会出现什么问题&&怎么解决脏读、不可重复读和幻读问题 --xunznux

时间:2024-09-02 21:51:04浏览次数:7  
标签:事务 Java 隔离 Read 数据 面试题 级别 View

文章目录


事务的隔离级别定义了多个事务之间的可见性和操作顺序,确保数据的完整性和一致性。SQL标准定义了四种隔离级别,每种隔离级别都对事务之间的干扰程度进行了不同的限制,防止脏读、不可重复读和幻读等问题。

四种事务隔离级别

  1. 未提交读(Read Uncommitted)

    • 描述:在此级别下,一个事务可以读取其他事务未提交的数据。这种隔离级别可能导致脏读问题,即读取到的值可能是其他事务修改但未提交的值。
    • 缺点:可能发生脏读。
    • 优点:性能最高。
  2. 已提交读(Read Committed)

    • 描述:在此级别下,一个事务只能读取到其他事务已提交的数据。未提交的更改对于其他事务不可见。这种级别避免了脏读,但可能会发生不可重复读。
    • 缺点:可能发生不可重复读。
    • 优点:大多数数据库的默认隔离级别(如Oracle)。
  3. 可重复读(Repeatable Read)

    • 描述:在此级别下,一个事务在开始时读取的数据,在整个事务期间都不会改变,即使其他事务进行了提交。这样可以避免不可重复读,但可能会发生幻读。
    • 缺点:可能发生幻读。
    • 优点:MySQL的默认隔离级别,能保证更高的事务一致性。
  4. 可串行化(Serializable)

    • 描述:这是最高的隔离级别,所有的事务依次执行,就像它们是串行化的一样。在这种情况下,可以完全避免脏读、不可重复读和幻读问题。
    • 缺点:并发性最差,性能最低。
    • 优点:保证事务的完整隔离。

MySQL中设置事务隔离级别

可以通过以下命令查看和设置MySQL的事务隔离级别:

  1. 查看当前隔离级别

    SELECT @@global.tx_isolation;
    

    或者

    SHOW VARIABLES LIKE 'transaction_isolation';
    
  2. 设置事务隔离级别

SET GLOBAL TRANSACTION ISOLATION LEVEL {level};

-- 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL {level};

-- 设置全局隔离级别为可重复读
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 设置当前会话隔离级别为可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; 

隔离级别可以是 'READ UNCOMMITTED', 'READ COMMITTED', 'REPEATABLE READ', 'SERIALIZABLE' 之一。
通过以上设置,可以在MySQL中调整事务的隔离级别,以满足不同应用场景的需求。

四种事务隔离级别在并行事务中可能会遇到的问题

隔离级别脏读 (Dirty Read)不可重复读 (Non-repeatable Read)幻读 (Phantom Read)
读未提交 (Read Uncommitted)可能发生可能发生可能发生
读已提交 (Read Committed)不会发生可能发生可能发生
可重复读 (Repeatable Read)不会发生不会发生可能发生
可串行化 (Serializable)不会发生不会发生不会发生

脏读、不可重复读和幻读

  • 脏读 (Dirty Read): 事务A读取了事务B未提交的数据,之后事务B回滚,导致事务A读取到了无效数据。
  • 不可重复读 (Non-repeatable Read): 事务A在读取同一行数据的不同时间点,得到的结果不同。原因是事务B在事务A的两次读取期间修改并提交了该行数据。
  • 幻读 (Phantom Read): 事务A在两次查询之间,事务B插入或删除了数据,导致事务A的两次查询结果行数不同。

三者区别

  • 脏读:重点在于读到了无效数据,原因是在读取最新数据后,这个最新数据被其他事务回滚了,脏读再次读取最新数据时无法再读取这一个数据了。数据是从有到无得变化。
  • 不可重复读:重点在于前后两次读取的同一行数据得到内容不同。原因是数据的更新,从版本1变化到版本2
  • 幻读:重点在于两次查询一种类型的数据时,查询结果行数不一致。原因是其他事务对这个类型的数据集合增加了新的数据或者删掉了旧的某些行数据,从集合A变成集合B

事务的隔离级别是怎么解决这三个问题的?

  1. 读未提交每次读取最新数据,没有解决这三个问题。是最低的隔离级别(没有隔离)。
  2. 读已提交,一个事务A只能读取到其他事务B已经提交(commit)的数据,事务B(transaction)在开始(begin)之后,它在事务期间执行的SQL都会产生结果,但是如果没有提交(commit)事务。在这个隔离级别下,A就无法读取到B的中间结果,因此,如果B在最后没有提交,而是回滚(rollback)事务,那么也不会出现脏读。但是,如果在事务A期间执行了两次查询,第一次查询查到了事务B对数据 a 的插入结果,第二次查询查到了事务C对数据a的更新结果。因此两次查询a的数据不一样,出现了不可重复读的问题。
    • 原因:读已提交是通过read view实现的。它在每次 select 时都会生成一个 Read View,因此事务A期间的两次读取同⼀条数据,前后两次读的数据会出现不⼀致,因为这期间另外⼀个事务C修改了事务B之前提交的 a 记录,并提交了事务C。
  3. 可重复读:可重复读(Repeatable Read)隔离级别的实现依赖于多版本并发控制(MVCC)。当事务启动时,会生成一个 Read View,这个 Read View 确保了在整个事务期间,普通的快照读(Snapshot Read)总是读取事务启动时看到的数据,即事务启动前的数据快照。因此,也就解决了不可重复度的问题。注意:select … for update 属于当前读,因此不会使用快照读的read View,而是读取最新的数据,如果因为这个导致前后读取数据不一致的问题,不属于不可重复读。
  4. 幻读:可重复读隔离级别仍然没有完全解决幻读问题。为什么这么说呢?如果在事务A启动后连续执行了两次普通的快照读。那么这两次查询不会发生幻读。但是如果在这两次查询期间,事务B插入了一条数据,然后事务A在第二次查询之前,尽管它第一次没有查到这条数据,但是仍然对它进行了更新操作,那么这条数据的 trx_id 就是A的 trx_id,因此,第二次查询就会查到这一条数据。发生了幻读。第二个例子:两次查询中,第一次使用快照读,第二次使用了当前读(select for update),如果在这期间其他事务B插入了新的数据并且提交,这个数据又刚好满足A的查询条件,由于当前读不会使用隔离级别生成的ReadView,而是使用最新的,就会发生幻读问题。
    • 怎么完全解决:通过串行化隔离级别(最高隔离),没有并行就不会出现并发问题,串行化隔离级别通过排它锁阻止了其他事务对当前事务所查询数据区间的修改。

Read View 是什么

Read View 是 MySQL 的 InnoDB 存储引擎在实现多版本并发控制(MVCC)时的一个关键概念。它用于确保在一个事务的整个生命周期内,快照读操作看到的数据是一致的。以下是 Read View 包含的信息及其在 MVCC 中的工作原理:

Read View 包含的信息

  1. m_ids(Min Transaction ID Set):

    • 这是在 Read View 创建时系统中所有活跃事务的事务 ID 列表。一个事务被认为是活跃的,如果它的状态是已启动但尚未提交或回滚。
  2. min_trx_id:

    • 这是 m_ids 中最小的事务 ID(即当前系统中最早启动但未提交的事务 ID)。它用于判断数据版本是否由某个还未提交的事务生成。
  3. max_trx_id:

    • 这是系统中下一个即将生成的事务 ID,它标识了在创建 Read View 时所有新启动事务的 ID 都会大于 max_trx_id。这个值主要用于判断哪些事务的修改在 Read View 生成时还不存在。
  4. creator_trx_id:

    • 这是创建 Read View 的当前事务的事务 ID。它用于在可见性判断中排除当前事务对数据的修改。

Read View 在 MVCC 中的工作原理

在 MVCC 中,每一行数据都包含了多个版本,每个版本关联一个事务 ID(trx_id),标识该版本是由哪个事务创建的。Read View 的作用就是判断某个版本的数据对当前事务是否可见。

工作流程
  1. 读取数据时生成 Read View:

    • 当一个事务第一次执行快照读(即普通的 SELECT 操作)时,InnoDB 会创建一个 Read View。
  2. 判断数据版本的可见性:

    • 对于每一行数据,InnoDB 会检查这个数据版本的 trx_id
    • 如果 trx_id < min_trx_id,说明这个数据版本是在所有活跃事务之前生成的,因此它对当前事务可见。
    • 如果 trx_id >= max_trx_id,说明这个数据版本是在 Read View 创建后生成的,因此它对当前事务不可见。
    • 如果 trx_idmin_trx_idmax_trx_id 之间,则需要进一步判断:
      • 如果 trx_id 属于 m_ids 集合中的某个活跃事务,说明这个版本的数据是由当前某个未提交的事务生成的,因此不可见。
      • 如果 trx_id 不在 m_ids 集合中,说明这个事务在 Read View 生成时已经提交,因此该版本的数据对当前事务可见。
  3. 读取合适的数据版本:

    • InnoDB 会根据上述判断,决定使用哪个版本的数据。如果当前版本不可见,则通过 roll_pointer 指针找到上一个版本,继续判断,直到找到一个对当前事务可见的版本为止。

总结

Read View 是 InnoDB 实现 MVCC 的核心,它确保了在事务执行过程中快照读操作的一致性。通过维护一个活跃事务的列表和相关的事务 ID 边界,Read View 能够精确地判断哪些数据版本对当前事务可见,哪些不可见,从而避免出现脏读、不可重复读等并发问题。

标签:事务,Java,隔离,Read,数据,面试题,级别,View
From: https://blog.csdn.net/weixin_44615954/article/details/141830491

相关文章

  • 详细分析MySQL事务日志(redo log和undo log)
    innodb事务日志包括redolog和undolog。redolog是重做日志,提供前滚操作,undolog是回滚日志,提供回滚操作。undolog不是redolog的逆向过程,其实它们都算是用来恢复的日志:1.redolog通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的......
  • 探索Groovy的Elvis操作符及其在Java中的替代方案
    在编程的世界里,我们经常需要处理变量的默认值问题,尤其是在变量可能为null的情况下。Groovy语言提供了一种优雅的方式来处理这种情况,那就是Elvis操作符。本文将探讨Elvis操作符的用法,并展示如何在Java中实现类似的功能。Elvis操作符简介Elvis操作符(?:)是Groovy语言中的一种......
  • 解耦利器 - Java中的SPI机制
    为什么需要SPI机制SPI和API的区别是什么SPI是一种跟API相对应的反向设计思想:API由实现方确定标准规范和功能,调用方无权做任何干预;而SPI是由调用方确定标准规范,也就是接口,然后调用方依赖此接口,第三方实现此接口,这样做就可以方便的进行扩展,类似于插件机制,这是SPI出现的需求背景。......
  • 解耦利器 - Java中的SPI机制
    为什么需要SPI机制SPI和API的区别是什么SPI是一种跟API相对应的反向设计思想:API由实现方确定标准规范和功能,调用方无权做任何干预;而SPI是由调用方确定标准规范,也就是接口,然后调用方依赖此接口,第三方实现此接口,这样做就可以方便的进行扩展,类似于插件机制,这是SPI出现的需求背景。......
  • JAVA 内部类与Lambda
    JAVA内部类与Lambda目录JAVA内部类与Lambda1内部类1.1内部类基础1.2私有成员内部类1.3静态内部类1.4局部内部类1.5匿名内部类2Lambda表达式2.1初识Lambda2.1.1无参无返回值抽象方法2.1.2Lambda有参无返回值抽象方法2.1.3Lambda无参有返回值抽象方法2.1.4有参有......
  • Java API:MATH
    JavaAPI:MATH目录JavaAPI:MATH1MATH2示例1MATHMath包含执行基本数字运算的方法;Math类提供的所有方法都是类方法;Math类方法变量和类型方法描述staticintabs(inta)返回int值的绝对值。staticdoubleceil(doublea)返回大于或等于参数且等于数学......
  • Java API:System
    JavaAPI:System目录JavaAPI:System1System2示例代码1SystemSystem类包含几个有用的类字段和方法。它无法实例化。System类提供的设施包括标准输入,标准输出和错误输出流;访问外部定义的属性和环境变量;加载文件和库的方法;以及用于快速复制阵列的一部分的实用方法。......
  • Java API:Object and Objects
    JavaAPI:ObjectandObjects目录JavaAPI:ObjectandObjects1Object1.1常用方法1.1Object类的toString方法1.1.1示例1.2equals1.2.1示例1.2.2面试题2Objects2.1示例1Object类Object是类层次结构的根。每个class都有Object作为超类。所有对象(包括数组)都实现此类的方......
  • Java API:BigDecimal
    JavaAPI:BigDecimal目录JavaAPI:BigDecimal1BigDecimal2示例1BigDecimalBigDecimal类使用户完全控制舍入行为。如果未指定舍入模式,并且无法表示确切的结果,则抛出异常;否则,可以通过向操作提供适当的MathContext对象来进行计算,以选择精度和舍入模式。在这两种情况下,都......
  • 浙江省会计人员继续教育刷课脚本-JavaScript编写
    脚本学习网站:浙江省会计人员继续教育:https://jxjy.czt.zj.gov.cn/front/jxjy.html脚本地址:浙江省会计人员继续教育-刷课脚本:https://greasyfork.org/zh-CN/scripts/506412-浙江省会计人员继续教育-刷课脚本教程1.插件安装(以MicrosoftEdge浏览器为例)打开最中间那个蓝色......