@Transactional事务管理

@Transactional事务管理简单介绍

@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控制的是事务的传播行为

事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制

image-20250909122522096

属性值 含义
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):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的
本站于2025年3月26日建立
使用 Hugo 构建
主题 StackJimmy 设计