Java后端笔记之@Transactional注解与log日志

这是 Spring 框架的核心注解,用于实现事务管理(保证一组数据库操作要么全部成功,要么全部失败),先理解基础概念再拆解参数:

一、"事务" 的核心场景

比如转账操作:A 扣钱 + B 加钱,这两个数据库更新必须同时成功或同时失败。如果只执行了 A 扣钱就报错,事务会回滚,A 的扣钱操作也会撤销,避免数据不一致。

二、注解参数拆解

1、参数

  • @Transactional 基础作用:给方法开启事务,Spring 会在方法执行前开启事务,执行成功后提交事务;
  • rollbackFor = Exception.class 关键参数:
    ①Spring 事务默认只对 RuntimeException(运行时异常,如空指针、数组越界)和 Error 回滚 ,对 Checked Exception(编译时异常,如 IOException、SQLException)不回滚;
    ②rollbackFor = Exception.class 表示 "扩大回滚范围"------ 只要方法抛出 任何继承自 Exception 的异常(包括运行时异常和编译时异常),事务都会回滚;
    ③如果不写这个参数,遇到 SQLException(比如数据库连接失败)这类编译时异常,事务不会回滚,会导致数据错误。
java 复制代码
@Service
public class OrderServiceImpl {

	private static final Logger log = LoggerFactory.getLogger(SScenarioServiceImpl.class);

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;

    // 重写父类方法 + 事务控制(所有异常都回滚)
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createOrder(OrderDTO orderDTO) throws Exception {
        // 操作1:保存订单主表
        orderMapper.insert(orderDTO);
        // 操作2:保存订单子表
        orderItemMapper.batchInsert(orderDTO.getItems());
        
        // 如果这里抛出任何Exception(比如空指针、数据库插入失败),上面两步操作都会回滚
        if (orderDTO.getAmount() <= 0) {
            throw new Exception("订单金额非法"); // 抛出Exception,事务回滚
        }
    }
}

如果保存订单子表时出错,订单主表的插入也会被撤销,保证数据一致性。

2、场景

这两个注解通常一起出现在:

  • 实现类重写接口的业务方法;
  • 这个方法涉及多步数据库操作(如增删改),需要事务保证数据一致性;
  • 要求任何异常都触发事务回滚,避免部分操作成功导致数据脏污。

三、注意

  • @Transactional 只对public 方法生效(Spring 代理机制决定),如果方法是private/protected,注解会失效;
  • 异常必须抛出到方法外部才会触发回滚:如果方法内部用 try-catch 捕获了异常但没重新抛出,事务不会回滚;
java 复制代码
// 错误示例:捕获异常不抛出,事务不会回滚
@Override
@Transactional(rollbackFor = Exception.class)
public void createOrder(OrderDTO orderDTO) {
    try {
        orderMapper.insert(orderDTO);
        throw new Exception("出错了");
    } catch (Exception e) {
        // 只打印日志,没抛出异常,事务会提交(数据错误)
        log.error("创建订单失败", e);
    }
}
  • rollbackFor 的值是异常类型,可以指定多个,比如 rollbackFor = {SQLException.class,IOException.class}。

四、log

为什么不用 System.out.println()?

这行代码的核心价值是替代原生的 System.out.println(),因为日志框架有这些优势:

  • 可以灵活控制日志级别(只输出错误 / 警告,不输出调试信息);
  • 日志可输出到文件、控制台、远程服务器等,且格式可配置;
  • 性能更好,支持异步日志。

可以用 Lombok 的 @Slf4j 或 Spring 的 @Log 注解自动生成 log 对象,省去手动定义的代码;

1、方法一

如果不定义直接写 log.error(...),编译器会报错:找不到符号 log,因为它不知道 log 是什么。

java 复制代码
public class SScenarioServiceImpl {
    // 第一步:定义日志对象(必须有)
    private static final Logger log = LoggerFactory.getLogger(SScenarioServiceImpl.class);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createOrder(OrderDTO orderDTO) {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 第二步:使用日志对象输出错误日志
            log.error("创建订单失败", e);
            throw e; // 抛出异常触发事务回滚
        }
    }
}

2、方法二(@Slf4j 注解)

使用 Lombok 的 @Slf4j 注解

这是日常开发中最常用的简化方式,添加 Lombok 依赖后,只需要加一个注解,编译器会自动帮你生成和上面一样的 log 对象:

java 复制代码
import lombok.extern.slf4j.Slf4j;

@Slf4j // 自动生成 private static final Logger log = ...
public class SScenarioServiceImpl {
    public void createOrder(OrderDTO orderDTO) {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 直接用 log,无需手动定义
            log.error("创建订单失败", e);
            throw e;
        }
    }
}

3、方法三(@Log 注解)

Spring Boot 3.x+ 的 @Log 注解

Spring 自身也提供了类似的简化注解,效果和 Lombok 一致:

java 复制代码
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.Log;

@Log // 自动生成 log 对象
@Component
public class SScenarioServiceImpl {
    // 直接使用 log.error(...)
}

4、总结

  • 不管是手动定义还是注解简化,最终都必须有一个 Logger 类型的 log 对象,才能调用 log.error()、log.info() 等方法;
  • log 对象命名是行业约定:几乎所有项目都用 log 作为变量名,不要写成 logger、logUtil 等,保持代码规范;
  • LoggerFactory.getLogger(SScenarioServiceImpl.class) 中的 Class参数不能错:它决定了日志输出时的 "类名标识",方便定位日志来源(比如日志里会显示 SScenarioServiceImpl这个类抛出的错误)。

总结

@Transactional(rollbackFor = Exception.class) 是 Spring 注解,给方法加事务控制,核心是所有 Exception 异常都会触发事务回滚,保证数据库操作的原子性;

相关推荐
时代的凡人13 小时前
0208晨间笔记
笔记
今天只学一颗糖13 小时前
1、《深入理解计算机系统》--计算机系统介绍
linux·笔记·学习·系统架构
饭碗、碗碗香18 小时前
【Python学习笔记】:Python的hashlib算法简明指南:选型、场景与示例
笔记·python·学习
Wils0nEdwards18 小时前
初中化学1
笔记
饭碗、碗碗香20 小时前
【Python学习笔记】:Python 加密算法全景指南:原理、对比与工程化选型
笔记·python·学习
对牛乱弹琴的秦始皇20 小时前
IoT MQ 连接失败的排查笔记
服务器·网络·笔记
S190121 小时前
一些资源整合笔记,后续会陆续更新
笔记
marteker21 小时前
X测试协作式人工智能驱动的社区笔记
笔记
时代的凡人1 天前
0210晨间笔记
笔记
扑火的小飞蛾1 天前
Oracle 分区表降低高水位(HWM)笔记
数据库·笔记·oracle