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

Spring事务管理:从原理到实战

🌟 一、为什么需要 Spring 的事务管理?

在没有 Spring 之前,Java EE 应用程序处理事务只有两种方式:

1. 全局事务(Global Transactions)—— EJB + JTA

  • 适用于跨多个资源的事务(比如:数据库 + 消息队列)
  • 使用 JTA(Java Transaction API),API 很复杂
  • 必须依赖 应用服务器(如 WebLogic、WebSphere)
  • 通常通过 EJB 的 CMT(容器管理事务)实现声明式事务
  • 缺点:太重、难测试、代码复用性差

✅ 优点:能跨资源
❌ 缺点:必须用 EJB、必须部署在应用服务器、开发效率低

2. 本地事务(Local Transactions)—— JDBC 或 Hibernate 自带事务

  • 比如用 connection.setAutoCommit(false) 开启事务
  • 简单,但只能用于单一资源(如一个数据库)
  • 不能参与全局事务(JTA)
  • 代码侵入性强(手动 commit/rollback)

✅ 优点:简单直接
❌ 缺点:无法跨资源、代码重复多、难以升级到分布式事务


✅ Spring 的解决方案:统一事务抽象模型

🎯 目标:让开发者写一次代码,可以在不同环境(单机/集群/应用服务器)下自由切换事务策略,而无需修改业务逻辑。

✔️ Spring 提供了什么?

特性说明
一致的编程模型不管底层是 JDBC、Hibernate、JPA 还是 JTA,API 都一样
声明式事务用注解 @Transactional 自动管理事务,无需写 try-catch-commit/rollback
编程式事务手动控制事务边界,更灵活
与数据访问层无缝集成和 JdbcTemplate、HibernateTemplate 等配合得天衣无缝
不依赖应用服务器即使不用 EJB 和 JTA,也能享受声明式事务

🔧 二、核心概念:Spring 事务抽象架构

Spring 的事务机制基于几个关键接口和类:

1. PlatformTransactionManager 接口(核心)

这是 Spring 事务的“管理者”,所有事务操作都通过它来完成。

public interface PlatformTransactionManager {TransactionStatus getTransaction(TransactionDefinition definition);void commit(TransactionStatus status);void rollback(TransactionStatus status);
}
常见实现类:
实现类用途
DataSourceTransactionManager用于 JDBC 或 MyBatis,单数据源
HibernateTransactionManager用于 Hibernate 框架
JpaTransactionManager用于 JPA(如 Hibernate 作为 JPA 实现)
JtaTransactionManager用于 JTA,支持多资源分布式事务(需应用服务器或 Atomikos)

💡 你可以像注入普通 Bean 一样配置它,完全解耦!


2. TransactionDefinition 接口(定义事务规则)

表示一个事务的属性配置,包括:

属性含义
Propagation(传播行为)方法被调用时如何处理事务(如:新建事务?加入已有?)
Isolation(隔离级别)脏读、不可重复读、幻读等问题的控制
Timeout(超时时间)事务最长运行时间,超时自动回滚
Read-only(只读)提示数据库优化查询性能
Rollback for…哪些异常触发回滚(默认是 RuntimeException)

3. TransactionStatus 接口(运行时状态)

代表当前事务的状态,可以用来:

  • 判断是否是新事务:isNewTransaction()
  • 设置回滚:setRollbackOnly()
  • 判断是否已完成:isCompleted()

📦 三、如何配置事务管理器?

Spring 支持多种数据访问技术,每种都有对应的事务管理器。

✅ 示例1:JDBC / MyBatis(单数据源)

<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="123456"/>
</bean><!-- 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean><!-- 开启注解事务支持 -->
<tx:annotation-driven transaction-manager="txManager"/>

✅ 示例2:Hibernate(本地事务)

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="mappingResources"><list><value>user.hbm.xml</value></list></property><property name="hibernateProperties"><value>hibernate.dialect=org.hibernate.dialect.MySQL8Dialect</value></property>
</bean><bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"/>
</bean><tx:annotation-driven transaction-manager="txManager"/>

✅ 示例3:JTA(分布式事务,跨数据库+MQ)

<!-- 从 JNDI 获取数据源(由应用服务器管理) -->
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDB"/><!-- 使用 JTA 事务管理器 -->
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/><tx:annotation-driven transaction-manager="txManager"/>

📝 注意:JTA 不关心具体资源,因为它依赖容器的全局事务协调器。


🧩 四、事务同步:资源如何绑定到事务?

当你在一个事务中多次访问数据库,Spring 要确保每次都使用同一个连接(Connection),否则事务就失效了。

Spring 是怎么做到的?

✅ 高层方案(推荐):

使用 Spring 封装的数据访问模板,如:

  • JdbcTemplate
  • HibernateTemplate
  • JpaRepository

这些模板内部会自动从当前事务上下文中获取已绑定的资源(如 Connection 或 Session),并保证线程安全。

✅ 低层方案(了解即可):

如果你直接使用原生 API(如 SessionFactory.openSession()),可以用工具类:

// 正确做法:获取与事务同步的 Connection
Connection conn = DataSourceUtils.getConnection(dataSource);// Hibernate 示例
Session session = SessionFactoryUtils.getSession(sessionFactory, true);

⚠️ true 表示参与事务、自动同步


❗ 特殊类:TransactionAwareDataSourceProxy

这是一个代理包装类,让你的旧代码(期望传入 DataSource)也能参与 Spring 事务。

<bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"><property name="targetDataSource" ref="dataSource"/>
</bean>

📌 一般不需要用,除非集成老系统。


📌 五、声明式事务 vs 编程式事务

类型方式适用场景
声明式事务@Transactional 注解或 XML 配置推荐!绝大多数业务方法
编程式事务手动调用 TransactionManager 控制事务复杂逻辑、条件判断是否开启事务

示例:声明式事务(最常用)

@Service
public class UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Transactional  // 开启事务public void transferMoney(String from, String to, double amount) {jdbcTemplate.update("UPDATE account SET balance = balance - ? WHERE name = ?", amount, from);// 如果这里抛出异常,上面的操作也会回滚jdbcTemplate.update("UPDATE account SET balance = balance + ? WHERE name = ?", amount, to);}
}

示例:编程式事务(灵活性高)

@Autowired
private PlatformTransactionManager txManager;public void transferWithProgrammaticTx() {DefaultTransactionDefinition def = new DefaultTransactionDefinition();def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);TransactionStatus status = txManager.getTransaction(def);try {// 业务操作jdbcTemplate.update("UPDATE account SET balance = balance - 100 WHERE name = 'A'");jdbcTemplate.update("UPDATE account SET balance = balance + 100 WHERE name = 'B'");txManager.commit(status); // 提交} catch (Exception e) {txManager.rollback(status); // 回滚}
}

🚀 六、Spring 如何改变传统规则?

“你不再需要应用服务器只是为了用声明式事务!”

以前现在(Spring)
想用声明式事务?必须用 EJB + 应用服务器只要用 @Transactional + Spring 就行
想换事务方式?要重写代码只改配置文件,代码不动
测试困难可以在单元测试中轻松模拟事务

✅ 即使将来需要分布式事务,也只需更换 PlatformTransactionManager 实现(如 JTA 或 Atomikos),业务代码不变


📚 七、总结:Spring 事务的五大优势

优势说明
✅ 一致性统一 API,无论 JDBC/Hibernate/JPA/JTA
✅ 声明式事务@Transactional 注解,零侵入
✅ 轻量级不依赖应用服务器
✅ 易测试可以在 Spring TestContext 中测试事务行为
✅ 灵活切换本地事务 ↔ 分布式事务,只需改配置

💡 学习建议

  1. 先掌握声明式事务@Transactional 是最常用的。
  2. 理解事务传播行为:特别是 REQUIRED, REQUIRES_NEW, NESTED
  3. 学会配置事务管理器:根据你用的技术选对 PlatformTransactionManager
  4. 结合日志调试事务:开启 DEBUG 日志看事务开启/提交/回滚过程。
  5. 避免常见坑
    • 私有方法加 @Transactional 无效(代理失效)
    • 同一类中方法调用绕过代理
    • 异常被捕获但没抛出,导致不回滚

📚 下一步学习推荐

  • Spring 官方文档 - Transaction Management
  • 《Spring 实战》第4章:事务管理
  • 视频课程:B站搜索 “Spring 事务源码解析”

如果你还想深入了解某个点,比如:

  • @Transactional 的传播行为详解
  • 事务失效的 10 种场景
  • Spring 事务底层原理(AOP + ThreadLocal)
  • 与 MyBatis 整合事务
  • 分布式事务解决方案(Seata、LCN、TCC)

欢迎继续提问!我可以为你逐个深入讲解。

http://www.dtcms.com/a/535929.html

相关文章:

  • 彩票类网站开发哪些网站可以做免费推广
  • AOI设置在光伏制造领域的核心应用
  • win7 VSCode 1.70设置R语言的版本,电脑上有两个版本
  • 大疆/地平线招聘要求参考:未来学习方向
  • MySQL忘记Root密码,详细找回密码步骤
  • Flutter UI组件跨端复用技术调研
  • MySQL安装避坑指南:从下载到启动的全平台避坑手册
  • wordpress 多站点错误自己做的网站本地调试
  • iOS描述文件功能解析
  • C++拓展:(一)计算器实现:从中缀表达式到逆波兰表达式
  • Linux小课堂: 网络配置详解之DHCP动态分配与静态IP地址设置
  • 政务AI大模型落地:聚焦四大场景,提升服务效率
  • 微美全息(NASDAQ:WIMI)双向跨链交互,搭建区块链互联互通“生态桥梁”
  • 郑州建网站价jquery 做网站
  • 【Rust实战】打造内存安全的网络代理:深入异步IO与并发编程
  • 公司网站建设是什么意思59一起做网站
  • 想让默认头像不再千篇一律,就顺手复刻了一下 GitHub 的思路
  • 《HTTP 安全与性能优化全攻略》
  • 【Web安全】OAuth2.0框架高频安全漏洞分析总结
  • 算法<C++>——双指针操作链表
  • Linux小课堂: SELinux安全子系统原理与Apache网站目录访问问题解决方案
  • 云计算学习(三)——子网划分
  • 回森统一客服服务 AI+数字技术引领自智网络迈入新阶段
  • 云计算概念及虚拟化
  • 域名信息查询网站广告设计总结
  • qq网站登录入口蒙古文政务网站建设工作汇报
  • Spring Boot3零基础教程,Kafka 的简介和使用,笔记76
  • Rust Web实战:构建高性能并发工具的艺术
  • Kafka 全方位技术文档
  • (场景题)Java 导出 Excel 的两种方式