1.事务
1.1 什么是事务
事务是一组操作的集合,是一个不可分割的操作
事务回把所有操作作为一个整体,一起向数据库提交或者是撤销操作的请求,所以这组操作要么同时成功,要么同时失败
1.2 为什么需要事务

2. Spring 中事务的视线
2.1 初步了解
开启事务(获取事务)
提交事务
回滚事务
Spring中内置了两个对象
-
DataSourceTranscationMapper 事务管理器,用来获取事务(开启事务)提交或回滚事务
-
TransactionDefintion 是事务的属性,在获取事务的时候需要将TransactionDefiniton 船体从而获取一个事务 TranscationStatus


数据库中成功添加
改为
dataSourceTransactionManager.rollback(transactionStatus);

数据可并没有新增数据
2.2 Spring 声明式事务 @Transctional
添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>

修改程序使之异常


@Transactional 作用:可以用来修饰方法或类
修饰方法时:只修饰public方法时才生效
修饰类时:对修饰的类中所有的public方法都生效
方法类被修饰时,在目标方法执行开始之前,会自动开启事务,方法执行结束之后,自动提交事务
如果发执行过程中,出现异常,且异常未被捕获,就进行事务回滚操作
如果异常被程序捕获,方法就被认为是成功执行,依然会提交事务

虽然程序错误了,但由于异常被不活了,所以事务依然得到了提交
如果想要事务回滚,有两种方法:
1.重新抛出一次

- 手动回滚事务


3. @Transactional 详解
@transactionsal 注解中的三个常见属性
-
rollbackFor:异常回滚属性,指定能够触发事务回滚的异常类型,可以指定多个类型
-
Isolation:事务的隔离级别,默认为 Isolation.DEFAULT
-
propagation:事务的传播机制,默认为Propagation.REQUIED
3.1 rollBackFor
@transactional默认只在遇到运行时异常和Error时才会回滚

java
@Transactional
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");
if (true){
throw new IOException();
}
return "r2";
}

虽然程序抛出了异常,但是事务依然进行了提交
如果需要所有的异常都回滚,需要配置 @treanscational 注解中的rollbackFor属性
java
@Transactional(rollbackFor = Exception.class)
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {
// ⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");
if (true){
throw new IOException();
}
return "r2";
}
结论:
在Spring的事务管理中,默认只在遇到运行时异常RuntimeException和Error时才会回滚
如果需要回滚指定类型的异常,可以通过rollbackFor属性来指定
3.2 事务隔离级别

3.2.1 Spring 事务隔离级别


Spring 中的事务隔离级别可以通过 @Transactional 中的 isolation属性进行设置
java
@Transactional(isolation = Isolation.READ_COMMITTED)
@RequestMapping("/r3")
public String r3(String name,String password) throws IOException {
//... 代码省略
return "r3";
}
3.3 Spring 事务传播机制
事务传播机制:多个事务方法存在调用关系时,事务是如何在这些方法间进行传播的
3.3.1 事务的传播机制有哪些
3.3.2 Spring 事务传播机制使用和各种场景延时
重点关注 REQUIRED(默认)和 REQUIRES_NEW
REQUIRED
java
@RequestMapping("/propaga")
@RestController
public class PropagationController {
@Autowired
private UserService userService;
@Autowired
private LogService logService;
@Transactional(propagation = Propagation.REQUIRED)
@RequestMapping("/p1")
public String r3(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
//记录操作⽇志
logService.insertLog(name,"⽤⼾注册");
return "r3";
}
}
对应的UserService和LogService都添加上 Propagation. REQUIRED)
java
@Slf4j
@Service
public class UserService {
@Autowired
private UserInfoMapper userInfoMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void registryUser(String name,String password){
//插⼊⽤⼾信息
userInfoMapper.insert(name,password);
}
}
java
@Slf4j
@Service
public class LogService {
@Autowired
private LogInfoMapper logInfoMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void insertLog(String name,String op){
int a=10/0;
//记录⽤⼾操作
logInfoMapper.insertLog(name,"⽤⼾注册");
}
}
运行程序,发现数据库没有插入任何数据
流程描述:
-
p1方法开始事务
-
用户注册,出入一条数据(执行成功)
-
记录操作日志,插入一条数据(出现异常)
-
事务回滚,因为共用同一个事务,数据都回滚了
REQUIRES_NEW
将上述UserService 和LogService中相关⽅法事务传播机制改为REQUIRES_NEW
运行程序,用户数据插入成功,日志数据插入失败
NEVER(不支持当前事务,抛异常)
修改UserService中对应⽅法的事务传播机制为NEVER
程序执行报错,没有数据插入
NESTED(嵌套事务)
将上述UserService 和LogService中相关⽅法事务传播机制改为NESTED
运行程序,没有任何数据输入
流程描述
-
Controller 中的p1 开始事务
-
UserService 用户注册,出入一条数据
-
LogService 记录操作日志,插入一条数据(出现异常)
-
由于是嵌套事务,LogService出现异常,全部回滚
NESTED和REQUIRED有什么区别?
java
@Service
public class LogService {
@Autowired
private LogInfoMapper logInfoMapper;
@Transactional(propagation = Propagation.NESTED)
public void insertLog(String name,String op){
try {
int a=10/0;
} catch (Exception e){
//回滚当前事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
//记录⽤⼾操作
logInfoMapper.insertLog(name,"⽤⼾注册");
}
重新运行程序,发现用户表数据添加成功,日志表添加失败
LogService 中的事务已经回滚,但是嵌套事务不会回滚嵌套之前的事务,也就是说嵌套事务可以实现部分回滚
REQUIRED 如果回滚就是回滚所有事务,不能实现部分事务回滚
整个事务如果全部执行成功,二者的结果是一样的.
如果事务⼀部分执行成功,REQUIRED加⼊事务会导致整个事务全部回滚.NESTED嵌套事务可以实 现局部回滚,不会影响上⼀个方法中执行的结果.
4. 总结
-
Spring中使用事务,有两种方式,编程式事务和声明式事务,其中声明式事务使用较多,在方法上添加 @Transactional 就可以实现
-
可以设置事务的隔离级别(isolation)
-
可以设置事务的传播机制(propagation)