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

spring boot中“编程式事务”与“声明式事务”对比


编程式事务与声明式事务对比

数据库事务流程

在这里插入图片描述

Spring数据库事务约定流程

在这里插入图片描述


1. 编程式事务(Programmatic Transaction)

特点

  • 通过代码显式控制事务的开始、提交和回滚。
  • 灵活性高,适合复杂事务逻辑(如嵌套事务、动态事务边界)。
  • 代码侵入性较强。

使用示例
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private TransactionTemplate transactionTemplate; // 1. 通过TransactionTemplate管理事务

    // 使用编程式事务
    public void createUserWithProgrammaticTransaction(User user) {
        transactionTemplate.execute(status -> { // 2. 执行事务操作
            try {
                userRepository.save(user); // 保存用户
                // 模拟业务逻辑,可能抛出异常
                if (user.getAge() < 0) {
                    throw new RuntimeException("年龄不能为负数");
                }
                return null;
            } catch (Exception e) {
                status.setRollbackOnly(); // 3. 手动设置回滚
                throw e;
            }
        });
    }
}

关键点说明

  1. TransactionTemplate:通过依赖注入获取,需配置PlatformTransactionManager
  2. 事务逻辑封装:通过execute方法传入TransactionCallback,实现事务内的操作。
  3. 手动回滚:通过status.setRollbackOnly()控制回滚逻辑。


2. 声明式事务(Declarative Transaction)

特点

  • 通过注解(@Transactional)或XML声明事务属性,由Spring AOP自动管理。
  • 代码简洁,符合“关注点分离”原则。
  • 适合大多数标准事务场景(如方法级事务控制)。

使用示例
@Service
@Transactional // 1. 类级别声明事务
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // 方法级别覆盖事务配置
    @Transactional(propagation = Propagation.REQUIRES_NEW) // 2. 自定义传播行为
    public void createUserWithDeclarativeTransaction(User user) {
        userRepository.save(user); // 保存用户
        if (user.getAge() < 0) {
            throw new RuntimeException("年龄不能为负数"); // 3. 异常自动触发回滚
        }
    }
}

关键点说明

  1. @Transactional注解
    • 支持类或方法级别声明,默认事务传播行为为REQUIRED
    • 异常自动回滚:默认回滚RuntimeException及其子类,可通过rollbackFor自定义。
  2. 传播行为
    • REQUIRES_NEW:新事务,忽略外部事务。
    • REQUIRED:如果存在事务则加入,否则新建。


3. 核心配置

启用事务管理
// 启动类添加@EnableTransactionManagement
@SpringBootApplication
@EnableTransactionManagement // 必须开启声明式事务支持
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
数据源配置(application.properties)
# 自动配置DataSource和TransactionManager(需引入Spring Boot Starter Data JPA/MyBatis等)
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update


对比表格

对比项编程式事务声明式事务优缺点
实现方式通过代码显式控制事务(如TransactionTemplateTransactionManager)。通过注解(@Transactional)或XML声明事务属性,由Spring AOP代理管理。编程式:灵活性高,但代码冗余;
声明式:简洁,但需遵守Spring规则。
事务边界手动定义事务开始和结束(如execute方法)。通过注解标注方法或类,Spring自动管理边界。编程式适合动态边界;声明式适合固定方法级控制。
回滚控制手动调用setRollbackOnly()或抛出异常触发回滚。默认基于异常类型回滚(如RuntimeException),可通过rollbackFor自定义。编程式更灵活;声明式需依赖注解配置。
传播行为通过Propagation枚举显式设置。通过@Transactional(propagation=...)声明。声明式配置更直观。
代码侵入性需嵌套事务逻辑代码,侵入性强。通过注解声明,几乎无侵入。声明式更符合“关注点分离”原则。
适用场景复杂事务逻辑(如嵌套事务、动态事务)、需精细控制事务生命周期的场景。标准事务场景(如单方法事务)、需快速实现事务管理的场景。声明式适合大多数业务;编程式用于特殊需求。
配置复杂度需注入TransactionTemplateTransactionManager,手动编写事务逻辑。仅需注解和启用@EnableTransactionManagement声明式配置简单,编程式需更多代码。

总结

选择建议
  1. 声明式事务(首选)

    • 适用于大多数标准场景,如方法级事务控制。
    • 示例:用户注册、订单提交等单方法事务。
  2. 编程式事务

    • 适用于需要复杂事务逻辑的场景,如:
      • 嵌套事务(REQUIRES_NEW需与外部事务隔离)。
      • 动态决定是否回滚(如根据业务状态而非异常)。
关键注意事项
  • Spring Boot自动配置:确保引入spring-boot-starter-data-jpaspring-boot-starter-mybatis-plus等依赖,自动配置DataSourceTransactionManager
  • 事务代理机制:声明式事务依赖Spring AOP代理,需注意以下问题:
    • 方法可见性@Transactional仅对公共方法生效,内部方法调用无法触发事务。
    • 代理类型:默认使用JDK动态代理,需接口;若需CGLIB代理,可添加@EnableAspectJAutoProxy(proxyTargetClass = true)

完整代码示例

1. 编程式事务完整代码
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PlatformTransactionManager transactionManager; // 1. 注入事务管理器

    public void createUserWithProgrammatic() {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(def); // 2. 开启事务

        try {
            userRepository.save(new User("张三", 25)); // 保存用户
            // 模拟业务逻辑,抛出异常
            if (true) {
                throw new RuntimeException("模拟业务异常");
            }
            transactionManager.commit(status); // 3. 提交事务
        } catch (Exception e) {
            transactionManager.rollback(status); // 4. 手动回滚
            throw e;
        }
    }
}
2. 声明式事务完整代码
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(rollbackFor = Exception.class) // 1. 声明事务,包含所有异常回滚
    public void createUserWithDeclarative() {
        userRepository.save(new User("李四", 30)); // 保存用户
        if (true) {
            throw new RuntimeException("模拟业务异常"); // 2. 触发自动回滚
        }
    }
}

核心配置代码

// 启动类
@SpringBootApplication
@EnableTransactionManagement // 2. 启用声明式事务
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
# application.properties
# 1. 数据源配置(Spring Boot自动配置TransactionManager)
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update

最终对比总结

方式推荐程度适用场景代码简洁性灵活性
编程式事务复杂事务逻辑(嵌套、动态控制)
声明式事务标准事务场景(方法级控制)

结论

  • 优先选择声明式事务,简洁且符合设计模式。
  • 仅在需要复杂控制时(如嵌套事务、动态回滚条件)使用编程式事务。

相关文章:

  • day18 学习笔记
  • leetcode146.LRU缓存
  • 全球消费理性化浪潮下:跨境电商品牌溢价体系面临重构
  • 深入解析异构计算:从原理到 C++ 实践
  • ubuntu22.04 如何安装 ch341 驱动
  • MySQL-触发器
  • QT基础:安装与简介
  • Unity插件SuperScrollView详解
  • 端到端语音识别案例
  • Docker部署sprintboot后端项目
  • Android 系统中,应用申请的权限相关信息介绍
  • 一文详解QT环境搭建:Windows使用CLion配置QT开发环境
  • 深度学习-153-DeepSeek之调用远程大模型API接口和可用的开源Deepseek服务
  • C#实现HTTP服务器:处理文件上传---解析MultipartFormDataContent
  • 26考研——线性表_ 线性表的链式表示_单链表(2)
  • OpenCV 图形API(或称G-API)(1)
  • 周学习总结
  • 本地后台运行redis服务
  • SpringMVC 拦截器(Interceptor)
  • 渗透测试:登录页面的测试-弱口令思路和实战
  • php网站怎么做静态化/宁德市人民医院
  • 免费php域名网站/友链交易网
  • 风中有朵雨做的云网站观看/bt种子磁力搜索引擎
  • 淘宝客建网站怎么做/扬州seo
  • 金融审核网站制作/网店推广营销方案
  • 做网站一般都是那些人 会做/360优化大师官方下载手机