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

spring 事务实战:声明式vs 编程式

------------------------------------------------------------------------------------------------------

在 Spring 中,事务管理有两种核心实现方式:声明式事务和编程式事务。它们各有适用场景,下面通过实战示例对比两者的实现方式和特点。

一、编程式事务(Programmatic Transaction)

编程式事务通过手动编写代码控制事务的开始、提交、回滚,灵活性高,但代码侵入性强。

实现方式

  1. 依赖 TransactionTemplate(推荐,简化代码)
  2. 直接使用 PlatformTransactionManager(底层 API,更灵活)
示例 1:使用 TransactionTemplate
 
 
配置 TransactionTemplate
需要在 Spring 配置类中注入事务管理器和 TransactionTemplate

 

java
 
运行
 
 
 
 
@Configuration
@EnableTransactionManagement
public class TransactionConfig {@Beanpublic TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {return new TransactionTemplate(transactionManager);}
}
 

二、声明式事务(Declarative Transaction)

声明式事务通过注解或 XML 配置声明事务规则,无需手动编写事务控制代码,侵入性低,是 Spring 推荐的方式。

实现方式

  1. 基于注解 @Transactional(主流)
  2. 基于 XML 配置(传统方式,较少使用)
示例 2:使用 @Transactional 注解
 
 
启用注解事务
需在配置类中添加 @EnableTransactionManagement 注解:

 

java
 
运行
 
 
 
 
@Configuration
@EnableTransactionManagement // 启用声明式事务
public class TransactionConfig {// 配置数据源和事务管理器(如DataSourceTransactionManager)
}
 

三、核心区别对比

维度编程式事务声明式事务
实现方式 手动编写代码(TransactionTemplate 或 PlatformTransactionManager 注解(@Transactional)或 XML 配置
代码侵入性 高(事务逻辑与业务逻辑耦合) 低(事务规则与业务逻辑分离)
灵活性 高(可动态控制事务边界) 中等(通过注解属性配置)
适用场景 复杂事务逻辑(如多阶段提交) 常规业务场景(如 CRUD 操作)
维护成本 高(需手动维护事务代码) 低(配置集中管理)

四、实战建议

  1. 优先使用声明式事务:通过 @Transactional 注解,代码更简洁,符合 Spring “非侵入式” 设计理念。
  2. 关键参数配置:
    • propagation:控制事务传播行为(如 REQUIREDREQUIRES_NEW)。
    • isolation:设置事务隔离级别(如 READ_COMMITTED)。
    • rollbackFor:指定需要回滚的异常类型(默认仅回滚 RuntimeException)。
  3. 编程式事务的合理使用:当需要动态决定事务边界(如根据条件提交或回滚)时,使用 TransactionTemplate
  4. 注意事项:
    • 声明式事务基于 AOP,需避免自调用导致事务失效(如同一类中方法调用)。
    • 编程式事务需手动处理异常,确保事务正确回滚。

------------------------------------------------------------------------------------------------------

在 Spring 事务管理中,声明式和编程式事务的选择直接直接直接影响系统的可靠性和可维护性,选错场景往往会导致事务失效、数据不一致等 “坑”。下面结合实战场景,分析两者的适用边界和典型错误案例。

一、声明式事务:简洁但有 “隐形陷阱”

声明式事务(@Transactional)通过 AOP 实现,无需侵入业务代码,适合大多数常规场景。但它的 “隐式规则” 如果被忽略,极易踩坑。

适用场景

  • 标准 CRUD 操作(如订单创建、用户注册)
  • 事务边界清晰的单一业务流程
  • 不需要动态控制事务行为的场景

典型踩坑案例

1. 自调用导致事务失效

 

java
 
运行
 
 
 
 
@Service
public class OrderService {// 外部调用此方法,事务生效@Transactionalpublic void createOrder() {// 内部调用本类方法,事务失效!updateStock(); }// 未加注解,且被本类方法调用public void updateStock() {// 库存更新逻辑(无事务保护)}
}
 

 

原因:@Transactional 基于 AOP 代理,同类内方法调用不会经过代理,导致事务注解失效。
解决:注入自身 Bean 或拆分服务类。

 

2. 异常被捕获,事务不回滚

 

java
 
运行
 
 
 
 
@Transactional
public void transfer() {try {// 扣减余额操作accountDao.debit();// 模拟异常int i = 1 / 0;// 增加余额操作accountDao.credit();} catch (Exception e) {// 捕获异常但未抛出,事务不会回滚!log.error("转账失败", e);}
}
 

 

原因:@Transactional 默认只在未捕获的 RuntimeException 时回滚。
解决:抛出异常,或配置 rollbackFor = Exception.class

 

3. 错误设置传播行为

 

java
 
运行
 
 
 
 
// 错误示例:嵌套事务使用 REQUIRES_NEW 导致数据不一致
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser() {// 更新用户信息userDao.update();// 调用日志服务(新建事务)logService.saveLog(); // 若此处失败,用户更新已提交!
}
 

 

原因:REQUIRES_NEW 会开启新事务,与父事务独立提交 / 回滚。
正确选择:根据业务需要选择传播行为(如默认 REQUIRED 适合大多数场景)。

二、编程式事务:灵活但需 “手动控险”

编程式事务(TransactionTemplate 或 PlatformTransactionManager)通过代码手动控制事务,适合复杂场景,但需开发者手动处理事务边界。

适用场景

  • 动态决定事务边界(如根据条件提交 / 回滚)
  • 多阶段事务(如分布式事务中的本地事务段)
  • 事务内需要复杂逻辑判断(如分支流程)

典型踩坑案例

1. 忘记手动回滚

 

java
 
运行
 
 
 
 
@Service
public class PaymentService {@Autowiredprivate TransactionTemplate txTemplate;public void refund() {txTemplate.execute(status -> {try {// 退款操作paymentDao.refund();// 调用第三方退款接口(失败)thirdPartyRefundService.refund(); } catch (Exception e) {// 忘记设置回滚!事务会默认提交!log.error("退款失败", e);}return null;});}
}
 

 

解决:异常时必须调用 status.setRollbackOnly()

 

2. 事务范围过大

 

java
 
运行
 
 
 
 
public void batchImport(List<Data> dataList) {txTemplate.execute(status -> {for (Data data : dataList) {// 批量插入10000条数据(事务范围过大)dataDao.insert(data);}return null;});
}
 

 

问题:长事务会导致数据库连接占用时间过长,引发性能问题。
解决:拆分事务(如每 1000 条数据一个事务)。

三、场景选择决策指南

业务场景推荐方式核心原因
简单 CRUD 操作 声明式 代码简洁,减少重复劳动
事务内有复杂分支判断 编程式 可动态控制事务行为
多服务调用且事务边界固定 声明式 注解配置传播行为更清晰
需要部分提交、部分回滚 编程式 细粒度控制事务边界
团队新手较多 声明式 降低手动控制出错概率

四、最佳实践

  1. 优先声明式,辅以编程式:常规业务用 @Transactional,复杂场景局部使用 TransactionTemplate
  2. 声明式事务关键配置:
    java
     
    运行
     
     
     
     
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED,rollbackFor = Exception.class, // 显式指定回滚异常timeout = 30 // 设置超时时间,避免长事务
    )
    
     
  3. 编程式事务模板:
    java
     
    运行
     
     
     
     
    txTemplate.execute(status -> {try {// 业务逻辑doBusiness();} catch (Exception e) {status.setRollbackOnly(); // 强制回滚throw new BusinessException("操作失败", e);}return null;
    });
    
     
  4. 避免混合陷阱:同一业务流程不要混合两种事务方式,易导致事务边界混乱。

总结

声明式事务的核心是 “约定优于配置”,但需熟悉其 AOP 底层机制;编程式事务的核心是 “手动控制”,但需严谨处理异常和事务边界。选择时需结合业务复杂度、团队经验和系统可靠性要求,才能避免 “选错场景就踩坑” 的尴尬。

------------------------------------------------------------------------------------------------------

 

------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------

http://www.wxhsa.cn/company.asp?id=1157

相关文章:

  • 【JPCS独立出版Fellow杰青云集】2025年先进材料与航空航天结构力学国际学术会议(AMASM 2025)
  • 算法-TSP旅行商问题-03 - jack
  • ArkTS
  • 一文读懂基因检测PLM、体外诊断试剂PLM的功能、价值、解决方案
  • ai本地部署工具有哪些?新手入门AI推荐这几个
  • 匿名内部类
  • 文件上传、分片上传结合antdProComponents表格展示,点击上传
  • 2025 年 PLM 市场新锐崛起:五家厂商以创新技术引领行业变革新路径
  • 2025 年国产 PLM 系统发展全景:厂商实力与核心功能深度解读
  • 开发效率翻倍!编码助手+云效 AI 评审如何破解代码质量与速度难题?
  • SSL部署完成,https显示连接不安全如何处理?
  • 各省简称
  • 完整教程:HDFS基准测试与数据治理
  • var code = 76cb2b4f-5a26-4a70-a3bf-dc8f2ae5162f
  • 解放双手!三端通用的鼠标连点神器
  • 用 C# 与 Tesseract 实现验证码识别系统
  • 【9月19日最终截稿,SPIE出版】2025年信息工程、智能信息技术与人工智能国际学术会议(IEITAI 2025)
  • Dockerfile:如何用CMD同时启动两个进程
  • 启动GA-Event Activated,结束GA-End Ability
  • VMware Avi Load Balancer 31.1.2 发布 - 多云负载均衡平台
  • C# WinForms 使用 CyUSB.dll 访问 USB 设备
  • NKOJ全TJ计划——NP3990
  • Linux redis 8.2.1源码编译
  • MarkDown学习
  • 202003_MRCTF_千层套娃
  • 基于MATLAB的粒子群算法优化广义回归神经网络的实现
  • MySql EXPLAIN 详解
  • Transformer完整实现及注释
  • 数据策略与模型算法
  • 25fall-cs101 作业图床 - Amy