mysql事务隔离级别和spring事务传播机制

news/2024/12/24 7:43:55/文章来源:https://www.cnblogs.com/leecoder5/p/18420820

一、事务并发会出现的三个问题

数据库事务具有ACID4个特性:

A:Atomic,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;

C:Consistent,一致性,事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100;

I:Isolation,隔离性,如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;

D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储。

对于两个并发执行的事务,如果涉及到操作同一条记录的时候,可能会发生问题。因为并发操作会带来数据的不一致性,包括脏读、不可重复读、幻读等。数据库系统提供了隔离级别来让我们有针对性地选择事务的隔离级别,避免数据不一致的问题。

1、Dirty reads--读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。

ORDER 事务A 事务B
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
2 BEGIN; BEGIN;
3 UPDATE table SET name="B" where id=1;
4 SELECT * FROM table WHERE id = 1;(读到name=B)
5 ROLLBACK;
6 SELECT * FROM table WHERE id = 1;(读到name=A)
7 COMMIT;
2、non-repeatable reads--数据不可重复读。比如事务B中两处读取数据name的值。在第一读的时候,name是A,然后事务A就把name的数据改成B,事务B再读一次,结果就发现,name竟然就变成B了,造成事务B数据混乱。
ORDER 事务A 事务B
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
2 BEGIN; BEGIN;
3 SELECT * FROM table WHERE id = 1;(读到name=A)
4 UPDATE table SET name="B" where id=1;
5 COMMIT;
6 SELECT * FROM table WHERE id = 1;(读到name=B)
7 COMMIT;
3、phantom reads--幻象读数据

可以看到,session A 里执行了三次查询,分别是 Q1、Q2 和 Q3。它们的 SQL 语句相同,都是 select * from t where d=5 for update。这个语句的意思你应该很清楚了,查所有 d=5 的行,而且使用的是当前读,并且加上写锁。现在,我们来看一下这三条 SQL 语句,分别会返回什么结果。

  1. Q1 只返回 id=5 这一行;

  2. 在 T2 时刻,session B 把 id=0 这一行的 d 值改成了 5,因此 T3 时刻 Q2 查出来的是 id=0 和 id=5 这两行;

  3. 在 T4 时刻,session C 又插入一行(1,1,5),因此 T5 时刻 Q3 查出来的是 id=0、id=1 和 id=5 的这三行。

其中,Q3 读到 id=1 这一行的现象,被称为“幻读”。也就是说,幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。

这里,我需要对“幻读”做一个说明:

  1. 在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。什么是当前读?除了快照读其他都是当前读。而当前读的规则,就是要能读到所有已经提交的记录的最新值。所以才会出现幻读的情况,查到新插入的记录

  2. 上面 session B 的修改结果,被 session A 之后的 select 语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。

针对MySQL InnoDB引擎的可重复读隔离级别,有两种方式避免幻读:

  1. 快照读(普通select语句),是通过MVCC 方式解决了幻读
  2. 当前读(select … for update),是通过next-key lock(记录锁+间隙锁)来解决幻读

二、四种隔离级别能解决的三个问题

1、Serializable:避免了一个事务中由于其他事务的插入操作造成的多次读取数据不一致的问题,避免了幻读,最严格的级别,事务串行执行,资源消耗最大;

2、REPEATABLE READ:保证了一个事务多次查询不会读取到已经由另一个事务提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。 也解决了部分幻读的情况。

3、READ COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。

4、Read Uncommitted:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。

三、PROPAGATION(spring事务传播机制)

  • PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。也就是说业务方法需要在一个事务中运行,如果
    业务方法被调用时,调用业务方法的行为(方法)已经处在一个事务中,那么就加入到该事务,否则为自己创建一个新的事务。
    (默认传播机制)

  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。也就是说如果业务方法在某个事务范围内被调用,
    则该方法成为该事务的一部分。如果业务方法在事务范围外被调用,则该方法在没有事务的环境下执行。

  • PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。也就是说业务方法只能在一个已经存在的事务中执行,
    业务方法不能发起自己的事务。如果业务方法在没有事务的环境下被调用,容器就会抛出例外。

  • PROPAGATION_REQUIRESNEW:新建事务,如果当前存在事务,把当前事务挂起。也就是说业务方法被调用时,不管是否已经存在事务,
    业务方法总会为自己发起一个新的事务。如果调用业务方法的行为(方法)已经运行在一个事务中,则原有事务会被挂起,新的事务
    会被创建,直到业务方法执行结束,新事务才算结束,原先的事务才会恢复执行。

  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,就把当前事务挂起。也就是说业务方法不需要事务。如果
    方法没有被关联到一个事务中,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,
    原先的事务便会恢复执行。

  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。也就是说业务方法绝对不能在事务范围内执行。如果业务
    方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。

  • PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按REQUIRED属性执行。
    它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对
    DataSourceTransactionManager事务管理器起效。

另外有一篇文章写的传播机制写的不错,附上链接>>>点击链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/799926.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电商系统的简单设计

订单模块 作为电商系统,首入眼帘的就是订单模块,也是电商基础的模块之一。订单流程包含了订单从下单到完成的整个流程,订单的状态如下:这里迎来了第一个问题,可以看到订单状态有非常多种,如果用if else去做判断,逻辑会非常多,这时候就需要用到状态机模式了,状态机如何使…

限流器的实践

背景 我们有一个业务场景是给学生发布考试,发布的过程不复杂,就是一个老师传递一些考试相关的参数过来,服务器自动给所有学生生成一份任务,但是在学生上交的时候会有个问题,就是成百上千的学生一起上交,会有并发流量的问题。 这里由于我们的考试可能会设计多个班级的联考…

易优cms 数据库连接失败,如何重新进行正确配置

当你遇到易优CMS(EyouCMS)数据库连接失败的问题时,可以按照以下步骤进行正确的配置和故障排除。 1. 检查数据库配置文件 易优CMS的数据库配置文件位于 application/database.php。你需要检查并修改该文件中的数据库配置信息。 2. 核对数据库账号和密码 确保数据库账号和密码…

在Windows10中使用rust的diesel库

介绍 最近在学习Actix Web时,需要用到数据库操作,简单尝试了一下diesel,也遇到了一些问题。在这里记录一下,供大家参考。 1.安装 根据Diesel官网介绍,使用cargo binstall安装diesel cli。 cargo binstall diesel_cli如果报错 error: no such command: `binstall` 需要先安…

易优eyoucms网站无法安装,数据库文件版本号(无)与CMS源码版本号(v1.3.1)不一致,点击查看!

解决方法比较简单, 可以找历史版本, 使用同版本数据库或者源码进行安装, 安装完成后操作升级。扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HTML5、CSS3、Javascript等。承接:企业仿站、网站修改、网站改版、BUG修复、问题处…

易优eyoucms网站添加自定义新建字段的时候报错

根据提供的错误信息 SQLSTATE[42000]: Syntax error or access violation: 1118 Row size too large. The maximum row size for the used table type not counting BLOBs is 65535. You have to change some columns to TEXT or BLOBs,这个错误表明数据库表的行大小超过了 My…

易优eyoucms网站下载的系统导入就数据库出问题了,如何升级数据库?

数据库版本需要一样 数据库有新建模型的 需要打补丁包再导入扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HTML5、CSS3、Javascript等。承接:企业仿站、网站修改、网站改版、BUG修复、问题处理、二次开发、PSD转HTML、网站被黑、…

易优eyoucms网站登录报错:Array and string offset access syntax with curly braces is deprecated

根据提供的错误信息 Array and string offset access syntax with curly braces is deprecated,这个错误提示表明当前使用的 PHP 版本不支持使用大括号 {} 来访问数组和字符串偏移量。这种语法在 PHP 7.4 之后被标记为已弃用。 以下是一些可能的解决步骤: 1. 切换 PHP 版本 尝…

易优eyoucms网站报错,\\core\\library\\think\\db\\Connection.php

报错 \\\\core\\\\library\\\\think\\\\db\\\\Connection.php 第 380 行左右 数据表或视图不存在,请联系技术处理。[错误代码] SQLSTATE[42S02]: Base table or view not found: 1146 Table eyoucms.ey_channeltype doesnt exist 根据提供的错误信息 SQLSTATE[42S02]: Base ta…

高等数学 3.3 泰勒公式

泰勒(Taylor)中值定理1 如果函数 \(f(x)\) 在 \(x_0\) 处具有 \(n\) 阶导数,那么存在 \(x_0\) 的一个邻域,对于该领域内的任一 \(x\) ,有 \[f(x) = f(x_0) + f^{}(x_0)(x - x_0) + \cfrac{f^{}(x_0)}{2!}(x - x_0)^2 + \cdots + \cfrac{f^{(n)}(x_0)}{n!}(x - x_0)^n + R_…

腾讯云TDSQL数据库认证值得考吗?来看看TDSQL证书有什么用

国内市场上的数据库产品有不少,很多大企业都有自己的数据库产品,比如金仓的KingBase、华为的OpenGauss、阿里云的PolarDB、达梦DM数据库等等,腾讯云也有自己的数据库产品,叫做TDSQL数据库,TDSQL数据库有两个分支:基于MySQL版 + 基于PostgreSQL版。腾讯云是国内知名的云平…

Maximum execution time of 30 seconds exceeded

遇到 Maximum execution time of 30 seconds exceeded 这个错误,通常是因为 PHP 脚本执行时间超过了设定的最大执行时间限制。这可能是由于脚本执行了耗时的操作,例如长时间的数据库查询或其他资源密集型任务。 以下是一些解决步骤: 1. 增加最大执行时间限制 可以在 PHP 配置…