事务管理:确保素材一致性的关键

事务

事务是一组操作的集合,是一个不可分割的操作

事务会把所有的操作作为一个整体,一起向数据库提交或者是撤销操作请求,所以这组操作要么同时成功要么同时失效

事务应用

比如转账操作:

1.账户 A 给 账户 B 转了 100元

2.账户 B 的账户 +100元

这是如果没有事务的话,就可能会出现第一步实现了,但是第二步没有实现,导致账户 A 的钱减少了,但是账户 B 却未到账的问题。

虽然事务没有办法去解决第二步为啥没有实现的这个问题,但是可是使得 B 要是没有收到钱的话,A 的账户就不会减少

要么一起成功,要么一起失败

事务的操作

事务的操作主要分为三步:

1.开启事务: start transaction/begin (一组操作前开启事务)

2.提交事务:commit 

3. 回滚事务: roolback

Spring 中事务的实现

Spring 中的事务操作分为两类:

1.编程式事务

需求:用户注册时在日志表中插入一条操作记录

数据准备:

-- 创建数据库
DROP DATABASE IF EXISTS trans_test;
CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;
-- 切换到目标数据库
USE trans_test;
-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (
    `id` INT NOT NULL AUTO_INCREMENT,
    `user_name` VARCHAR (128) NOT NULL,
    `password` VARCHAR (128) NOT NULL,
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now() ON UPDATE now(),
    PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARACTER SET = utf8mb4 COMMENT = '用户表';
-- 操作日志表
DROP TABLE IF EXISTS log_info;
CREATE TABLE log_info (
    `id` INT PRIMARY KEY auto_increment,
    `user_name` VARCHAR ( 128 ) NOT NULL,
    `op` VARCHAR ( 256 ) NOT NULL,
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now() ON UPDATE now()
) DEFAULT charset 'utf8mb4';

代码准备:

配置文件

实体类

Mapper

Service

Controller

Spring 编程式事务

Spring 手动操作事务 和 Mysql 操作事务类似,有 3 个重要操作步骤:

开启事务

提交事务

回滚事务

数据库插入成功

我们打开回滚来看看

虽然 注册成功了,但是数据库并没有新增数据

2.声明式事务 @Transactional

声明式事务实现只需在事务的方法上添加 @Transactional 注解就可以实现了

无需手动开启事务和提交事务,进行方法时自动开启事务,方法执行完会自动提交事务,如果中途发生了没处理的异常会自动回滚事务

我们试一下异常会咋样

@Transactional 作用

它可以用来修饰方法 和 类:

修饰方法时:只有修饰 public 方法时才能生效

修饰类时:对 @Transactional 修饰的类中所有的 public 方法都生效

需要注意的是我们前面说出现异常没有处理时,就会回滚,但要是将异常给捕获了的话,方法会被认为成功执行,依然会提交事务

我们试着捕获一下:

如果我们要事务进行回滚有两种方法:

1.重新抛出异常

2.手动回滚事务

使用 

TransactionAspectSupport.currentTransactionStatus()

来获取事务,并且设置回滚

@Transactional 

@Transactional 中常见的三个属性:

1.rollbackFor

异常回滚属性,指定能够出发事务回滚的异常类型

@Transactional  默认只在遇到运行时异常和Error时才会回滚,非运行时异常不会滚,既 Exception 的子类中,除了 RuntimeException 及其子类

出现了异常,但是并没有出发回滚

我们需要所有的异常都进行回滚,通常需要配置 @Transactional,rollbackFor 指定出现何种异常类型时事务进行回滚

现在在出发这种类型的异常就进行了回滚了

2.Isolation

事务隔离级别

读未提交

读提交

可重复读

串行化

这在 MySQL 那里已经做过详细的介绍

Spring 事务隔离级别

序号隔离级别常量说明对应 SQL 标准隔离级别
1Isolation.DEFAULT以连接的数据库的事务隔离级别为主-
2Isolation.READ_UNCOMMITTED读未提交READ UNCOMMITTED
3Isolation.READ_COMMITTED读已提交READ COMMITTED
4Isolation.REPEATABLE_READ可重复读REPEATABLE READ
5Isolation.SERIALIZABLE串行化SERIALIZABLE

Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进行设置

3.propagation

事务的传播机制就是:多个事务方法存在调用关系中,事务是如何在这些方法间进行传播的

比如有两个方法 A 和 B 都被 @Transactional  修饰,A 方法调用了 B 方法

A 方法运行时开启了事务,调用 B方法 的时候,B 本身也有事务,这个时候是加入 方法A  的事务 还是创建一个新的事务,这就涉及到了 事务的传播机制

事务隔离级别是解决多个事务同时调用一个数据库的问题

事务传播机制解决的是一个事务在多个节点中传递的问题

事务的传播机制有哪些

Spring 中事务传播机制可以通过 @Transactional 中的 propagation 属性来制定传播行为

Spring 中事务传播机制有 7 种:

序号事务传播行为说明
1Propagation.REQUIRED默认传播级别。若当前存在事务,加入该事务;若不存在,创建新事务。
2Propagation.SUPPORTS若当前存在事务,加入该事务;若不存在,以非事务方式运行。
3Propagation.MANDATORY强制要求当前存在事务,若不存在则抛出异常。
4Propagation.REQUIRES_NEW无论当前是否存在事务,均创建新事务;若当前有事务,将其挂起。内部事务与外部事务相互独立。
5Propagation.NOT_SUPPORTED以非事务方式运行;若当前存在事务,将其挂起。
6Propagation.NEVER以非事务方式运行;若当前存在事务,抛出异常。
7Propagation.NESTED若当前存在事务,创建嵌套事务运行;若不存在,等价于 Propagation.REQUIRED。
对比项Propagation.REQUIREDPropagation.NESTED
执行成功时结果与 NESTED 一致结果与 REQUIRED 一致
部分执行成功时会导致整个事务全部回滚可实现局部回滚,不影响上一个方法的执行结果

posted @ 2025-11-25 17:47  yangykaifa  阅读(3)  评论(0)    收藏  举报