当前位置: 首页 > 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.sczhlp.com/news/90988/

相关文章:

  • 杭州模板建站定制东莞东城国际酒店
  • 删除网站备案深圳手机网站建设多少钱
  • 怎么在网站上面做悬浮广告做网站 做应用
  • 物联网网站开发做汽车价格的网站
  • 重庆哪个网站建设比较好.htaccess 伪静态 wordpress
  • 企业对比网站网站建设背景朝阳
  • solo博客容器化运行访问
  • 绍兴网站建站模板网站flash
  • 科讯cms怎么做网站地图泰州网站建设定制
  • 哪些网站可以做淘宝店招做企业网站需要购什么
  • 营销型网站建设设计服务nginx 404 wordpress
  • 建设银行青海省分行招聘网站wordpress通栏
  • 湖南建设工程竣工备案表查询网站二手交易平台
  • 安庆商城网站开发网络营销策划的方法
  • 上海建筑设计公司网站做网站团队
  • wordpress等级seo外推
  • 网站搜索引擎优化主要方法福山区建设工程质量检测站网站
  • Flutter应用架构设计:基于Riverpod的状态管理最佳实践
  • P12502 「ROI 2025 Day1」天狼星的换班 「线段覆盖问题」
  • 动态规划DP问题详解,超全,思路全收集
  • SQL入门与实战
  • day05 课程
  • 学校网站设计的作用建立网站难吗
  • 网站建设佳木斯快速做网站公司报价
  • 企业门户网站云服务器配置要求小程序代码怎么获取
  • 夏天做啥网站能致富苏州市建设工程交易中心网站
  • 全国建设部网站官网会python做网站
  • ArkTS
  • 贵阳网站建设哪家网页布局的基本概念
  • 大型门户网站建设效果做网站多少钱大概