当前位置: 首页 > web >正文

Spring 事务管理核心机制与传播行为应用

Spring 事务详解


一、Spring 事务简介

Spring 事务管理基于 AOP(面向切面编程)实现,通过 声明式事务(注解或 XML 配置)统一管理数据库操作,确保数据一致性。核心目标:保证多个数据库操作的原子性(要么全部成功,要么全部回滚)。

核心优势

  • 解耦业务代码与事务管理:通过注解配置,无需侵入业务逻辑。

  • 支持多种事务管理器:如 JDBC、Hibernate、JPA 等。

  • 灵活的事务传播行为:控制事务的边界和嵌套逻辑。


二、 案例:银行账户转账

需求:用户 A 向用户 B 转账,需保证扣款和存款操作同时成功或失败。

代码实现
(1) 业务层接口与实现类
public interface AccountService {void transfer(String fromUser, String toUser, int money);
}@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Transactional  // 开启事务管理@Overridepublic void transfer(String fromUser, String toUser, int money) {// 扣款accountDao.reduceMoney(fromUser, money);// 模拟异常(事务应回滚)// int i = 1 / 0;  // 存款accountDao.addMoney(toUser, money);}
}
(2) 数据层(DAO)
@Repository
public class AccountDaoImpl implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void reduceMoney(String user, int money) {String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";jdbcTemplate.update(sql, money, user);}public void addMoney(String user, int money) {String sql = "UPDATE account SET balance = balance + ? WHERE username = ?";jdbcTemplate.update(sql, money, user);}
}

三、Spring 事务核心配置

步骤 1:启用事务管理
  • Spring Boot:默认已启用事务,无需额外配置。

  • 非 Spring Boot:在配置类添加 @EnableTransactionManagement

    @Configuration
    @EnableTransactionManagement  // 开启注解式事务驱动
    public class AppConfig { ... }
步骤 2:配置事务管理器
  • Spring Boot:自动配置 DataSourceTransactionManager

  • 手动配置

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
    }
步骤 3:使用 @Transactional 注解
  • 作用位置:类(所有方法生效)或方法。

  • 关键属性

    • propagation:事务传播行为(默认 REQUIRED)。

    • isolation:事务隔离级别(默认 DEFAULT,跟随数据库)。

    • rollbackFor:指定触发回滚的异常类型。

    • timeout:事务超时时间(秒)。


四、Spring 事务角色

角色说明
事务管理器PlatformTransactionManager 接口的实现类(如 DataSourceTransactionManager)。
事务定义通过 @Transactional 注解或 XML 配置定义事务属性(传播行为、隔离级别等)。
事务状态事务的运行时状态(如是否是新事务、是否回滚)。


五、Spring 事务属性

属性说明常用值
propagation事务传播行为(控制事务边界)REQUIRED(默认)、REQUIRES_NEWNESTEDSUPPORTS 等。
isolation事务隔离级别(解决并发问题)DEFAULTREAD_COMMITTEDREAD_UNCOMMITTEDREPEATABLE_READ 等。
timeout事务超时时间(秒),超时自动回滚。默认 -1(无超时)。
readOnly是否只读事务(优化数据库性能)。true 或 false(默认)。
rollbackFor触发回滚的异常类型(默认仅回滚 RuntimeException)。如 rollbackFor = Exception.class
noRollbackFor不触发回滚的异常类型。如 noRollbackFor = NullPointerException.class

六、 事务传播行为(Propagation)

控制事务方法之间如何相互影响,常见行为:

传播行为说明
REQUIRED如果当前存在事务,则加入该事务;否则新建一个事务(默认行为)。
REQUIRES_NEW无论当前是否存在事务,都新建一个事务,挂起当前事务(独立提交)。
SUPPORTS如果当前存在事务,则加入;否则以非事务方式执行。
NESTED如果当前存在事务,则嵌套在子事务中执行(可部分回滚)。


七、案例:转账业务追加日志

需求:在转账操作后记录日志,且日志记录必须成功(即使转账失败也要记录)。

代码实现
@Service
public class LogService {@Autowiredprivate LogDao logDao;// 使用 REQUIRES_NEW 传播行为:独立事务@Transactional(propagation = Propagation.REQUIRES_NEW)public void addLog(String logInfo) {logDao.insertLog(logInfo);// 即使转账失败,日志也会提交}
}@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Autowiredprivate LogService logService;@Transactional@Overridepublic void transfer(String fromUser, String toUser, int money) {accountDao.reduceMoney(fromUser, money);accountDao.addMoney(toUser, money);// 记录日志(独立事务)logService.addLog("转账操作:" + fromUser + " 向 " + toUser + " 转账 " + money);}
}

关键点

  • 日志方法 addLog 使用 REQUIRES_NEW,确保日志事务独立提交。

  • 即使转账事务回滚,日志事务仍会提交。


八、事务配置示例

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,timeout = 30,rollbackFor = {SQLException.class, IOException.class}
)
public void businessMethod() { ... }

九、 常见问题

  1. 事务不生效

    • 检查是否启用事务管理(@EnableTransactionManagement)。

    • 确保 @Transactional 注解应用在 public 方法上。

    • 确认异常类型是否触发回滚(默认仅回滚 RuntimeException 和 Error)。

  2. 事务传播行为错误

    • 嵌套事务中错误使用 REQUIRES_NEW 可能导致事务过多,影响性能。


十、总结

  • 核心注解@EnableTransactionManagement(启用事务)、@Transactional(定义事务属性)。

  • 事务传播行为:根据业务需求选择合适的行为(如 REQUIRED 或 REQUIRES_NEW)。

  • 事务管理本质:基于 AOP 动态代理实现,通过事务管理器控制数据库连接。

进一步实践:结合具体业务场景测试不同传播行为和隔离级别,深入理解事务的边界控制!

http://www.xdnf.cn/news/709.html

相关文章:

  • Keil MDK 编译问题:function “HAL_IncTick“ declared implicitly
  • 牛客java练习题
  • OpenCV 图像调整指南
  • CSS 预处理器:Sass 升级版本 浅学
  • Edge Impulse 训练openMV分类模型(字母+数字)
  • AnimateCC基础教学:制作一个打地鼠简化版
  • 第37讲|AI+农业气象建模:预测极端天气对农业的影响
  • Linux 动、静态库的实现
  • 【代码解读】开源模型 minimind之pretrain
  • Java29:Spring MVC
  • 认识MCP Function Calling AI Agent
  • Redis——内存策略
  • 对于网络资源二级缓存的简单学习
  • 第十章 继承与派生
  • C++ 构造函数调用顺序以及什么是虚析构函数?为什么需要它?
  • Ubuntu下安装和卸载MySQL
  • 简单使用MCP
  • PCA 降维实战:从原理到电信客户流失数据应用
  • 一键升级OpenSSH/OpenSSL修复安全漏洞
  • 【LINUX操作系统】线程基础与分页式存储管理
  • C++初阶-类和对象(中)
  • 【数据分析实战】使用 Matplotlib 绘制散点图
  • Android音视频开发
  • 【网络】通过Samba实现Window挂在Linux服务器路径
  • 【Windows10下PP-OCRv4部署指南‌】
  • 云点数据读写
  • 33-公交车司机管理系统
  • Kubernetes控制平面组件:调度器Scheduler(二)
  • MySQL:9.表的内连和外连
  • 字节头条golang二面