@Transactional事务管理
简介
@Transactional的作用:将方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务
可以加的位置:方法上、类上、接口上
建议加在需要多次操作数据库的业务层方法上
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Transactional
@Override
public void save(Emp emp) {
// 保存员工的基本信息
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(emp);
int a = 1 / 0; // 制造异常,测试事务
// 保存员工工作经历信息
List<EmpExpr> exprList = emp.getExprList();
if (!CollectionUtils.isEmpty(exprList)) {
// 遍历集合,为empId赋值
exprList.forEach(empExpr ->
empExpr.setEmpId(emp.getId())
);
empExprMapper.insertBatch(exprList);
}
}
|
上述代码执行到第9行会报错,如果没有@Transactional进行事务管理,就会导致员工信息被保存,但对应的工作经历却丢失了
有了事务管理后,只要这个方法中有一步报错,就会进行自动回滚,让数据库回到执行该方法前的状态
进阶
rollbackFor
@Transactional事务管理默认出现运行时异常RuntimeException才会回滚
如果手动抛出非运行时异常就会正常提交,不会回滚
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Transactional
@Override
public void save(Emp emp) throws Exception {
// 保存员工的基本信息
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(emp);
if ( true ) {
throw new Exception("测试事务");
}
// 保存员工工作经历信息
List<EmpExpr> exprList = emp.getExprList();
if (!CollectionUtils.isEmpty(exprList)) {
// 遍历集合,为empId赋值
exprList.forEach(empExpr ->
empExpr.setEmpId(emp.getId())
);
empExprMapper.insertBatch(exprList);
}
}
|
Exception就是非运行时异常,此时运行代码后,员工基本信息会被正常提交,而员工工作经历会丢失
此时就可以使用rollbackFor进行指定要回滚的异常
1
|
@Transactional(rollbackFor = { Exception.class })
|
只指定一个时,{}可以不加
此时会正常进行回滚,员工基本信息不会被保存
propagation
propagation控制的是事务的传播行为
事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制

| 属性值 |
含义 |
| REQUIRED |
【默认值】需要事务,有则加入,无则创建新事务 |
| REQUIRES_NEW |
需要新事务,无论有无,总是创建新事务(两个方法在独立的事务中运行,互不影响) |
| SUPPORTS |
支持事务,有则加入,无则在无事务状态中运行 |
| NOT_SUPPORTED |
不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
| MANDATORY |
必须有事务,否则抛异常 |
| NEVER |
必须没事务,否则抛异常 |
示例:
需求:在新增员工信息时,无论是成功还是失败,都要记录操作日志
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
@Transactional(rollbackFor = { Exception.class })
@Override
public void save(Emp emp) throws Exception {
try {
// 保存员工的基本信息
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(emp);
int a = 1 / 0; // 制造异常,测试事务
// 保存员工工作经历信息
List<EmpExpr> exprList = emp.getExprList();
if (!CollectionUtils.isEmpty(exprList)) {
// 遍历集合,为empId赋值
exprList.forEach(empExpr ->
empExpr.setEmpId(emp.getId())
);
empExprMapper.insertBatch(exprList);
}
} finally {
// 记录操作日志
EmpLog empLog = new EmpLog(null, LocalDateTime.now(), "新增员工:" + emp);
empLogService.insertLog(empLog);
}
}
// empLogService实现类中的insertLog方法
@Override
public void insertLog(EmpLog empLog) {
empLogMapper.insert(empLog);
}
|
如果代码如上,运行结束后记录操作日志的行为也会回滚,无法满足需求
为了让insertLog方法作为一个单独的事务,不被save方法的事务影响,就需要让insertLog方法在使用时创建一个新事务,此时就需要给insertLog方法添加事务管理,并如下修改propagation的值
1
2
3
4
5
|
@Transactional(propagation = Propagation.REQUIRES_NEW) // 在新事务中运行
@Override
public void insertLog(EmpLog empLog) {
empLogMapper.insert(empLog);
}
|
修改后,即可满足需求
事务的四大特性(ACID)简介
- 原子性(Atomicity):事务是不可分割的最小单元,要么全部成功,要么全部失败
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态
- 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的