MySQL数据库事务隔离级别、Spring事物传播行为

发布时间 2023-11-03 20:24:19作者: wyy1

MySQL数据库事务隔离级别

1 什么是事务

事务就是保障一系列的操作统一执行,要嘛全部成功,要嘛全部失败。

事务由单独单元的一个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条SQL语句一旦执行失败或产生错误,整个单元将会回滚。所有受到影响的数据将返回到事物开始以前的状态;如果单元中的所有SQL语句均执行成功,则事物被顺利执行

2、事务的基本要素(ACID)

1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。分为强一致性(银行转账)、弱一致性、最终一致性等

3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

MySQL事务隔离级别理解

隔离级别

1、读不提交(Read Uncommited,RU)
这种隔离级别下,事务间完全不隔离,会产生脏读,可以读取未提交的记录,实际情况下不会使用。

2、读提交(Read commited,RC)
本事务读取到的是最新的数据(其他事务提交后的)。问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读)

3、可重复读(Repeatable Read,RR)【MySQL 默认的级别】
在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同一个事务同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象

4、 串行化(SERIALIZABLE)。读操作会隐式获取共享锁,可以保证不同事务间的互斥

理解和示例

对于单线程来说,事务很好理解 ACID也都很好理解。但对于多线程并发访问数据库的情况就会涉及到mysql ACID里高级一点的特性 隔离性。
例如一个场景:
Java项目 多线程请求 mysql数据库,毕竟相对于Java程序来说 mysql 就相当一个共享的资源,那么并发情况下 对于共享资源就要考虑数据安全问题。你也不能就是这个事务就完全用 mysql最高级别的隔离级别 那样会使mysql数据库性能减慢,所以mysql的隔离级别就会分等级。
testA表、testB表
如图:

线程1 事务1
事务1内容
(1)insert into testA (id,name) values(1,“张三”)
(2)update testA set testA.name=“王五” where testA.name=“张三”

线程2 事务2
事务2内容
(3)select * from testA where testA.name=“张三”
(4)update testB set testB.name=“李四” where testA.name=“张三”

线程1走到(2)处 但没有提交,此时线程2走到(3)处 ,此时如果mysql没有事务隔离 那么就会出现问题,导致数据出问题。

这就是mysql 事务隔离的作用 并且隔离还分等级 mysql事务隔离级别

如果上面的例子 设置成 读不提交(Read Uncommited,RU),那么数据大概率是会出现问题的。
如果上面的例子 设置成 串行化(SERIALIZABLE), 不会出问题 但是太影响效率

Spring事物传播行为

1 spring事务传播行为

spring用代码实现了 操作mysql数据库的行为,spring的事务代码 实现了操作mysql事务的行为。
个人理解 就是用代码实现了适当的复制mysql的事务的过程,当然中间还有一些具体的技巧就不多说了。
比如 一个方法A加了spring事务注解,另一个方法B没有加注解, 但是我又想让方法B拥有事务,那么我就规定一个注解 称之为 spring的事务传播注解。规定spring的事务传播特性。加上这个注解方法B就能拥有方法A的事务了,我的目的就达到了 少写了一些代码。

2 Spring有7中事物传播行为:由@Transaction(Propagation=XXX)设置决定:

1)REQUIRED(required):如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。即:不管内部事物还是外部事物,只要发生异常,全部回滚,默认是这种传播
2)REQUIRES_NEW(requires_new):新建事务,如果当前存在事务,把当前事务挂起。
3)SUPPORTS(supports):支持当前事物,如果没有事物,就以非事物方式执行。
4)MANDATORY(mandatory):使用当前事物,没有就抛出异常
5)NOT_SUPPORTED(not_supported):使用非事物的方式执行,如果当前存在事物,就把当前事物挂起
6)NEVER(never):以非事物方式执行,如果当前事物存在,则抛出异常
7)NESTED(nested):如果当前存在事物,则嵌套事物内部执行;如果当前没有事物,则执行与PROPAGATION_REQUIRED类似操作