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

SpringBoot 编程式事务使用

目录

  • 1. 简介
  • 2. TransactionTemplate 方式
  • 3. TransactionManager 方式
  • 4. 事务传播行为
  • 5. 事务隔离级别
  • 6. 最佳实践
  • 7. 常见问题与解决方案

1. 简介

编程式事务管理是通过编写代码来管理事务,相对于声明式事务(@Transactional注解),它提供了更细粒度的事务控制。在 SpringBoot 中,主要有两种实现方式:

  • 使用 TransactionTemplate
  • 直接使用 TransactionManager

2. TransactionTemplate 方式

TransactionTemplate 是最简单的编程式事务实现方式,它对底层事务 API 进行了封装,使用起来更加便捷。

2.1 基本配置

@Configuration
public class TransactionConfig {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Bean
    public TransactionTemplate transactionTemplate() {
        TransactionTemplate template = new TransactionTemplate();
        template.setTransactionManager(transactionManager);
        // 设置默认的事务传播行为
        template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        // 设置默认的事务隔离级别
        template.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
        // 设置默认超时时间
        template.setTimeout(30);
        return template;
    }
}

2.2 基本使用示例

@Service
@Slf4j
public class UserService {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(User user) {
        // 使用 execute 方法执行有返回值的事务操作
        return transactionTemplate.execute(status -> {
            try {
                User savedUser = userRepository.save(user);
                // 模拟其他操作
                updateUserProfile(savedUser);
                return savedUser;
            } catch (Exception e) {
                // 手动标记事务回滚
                status.setRollbackOnly();
                log.error("创建用户失败", e);
                throw new RuntimeException("创建用户失败", e);
            }
        });
    }
    
    public void batchCreateUsers(List<User> users) {
        // 使用 executeWithoutResult 方法执行无返回值的事务操作
        transactionTemplate.executeWithoutResult(status -> {
            try {
                for (User user : users) {
                    userRepository.save(user);
                }
            } catch (Exception e) {
                status.setRollbackOnly();
                log.error("批量创建用户失败", e);
                throw new RuntimeException("批量创建用户失败", e);
            }
        });
    }
}

3. TransactionManager 方式

直接使用 TransactionManager 提供了更细粒度的事务控制,但使用起来相对复杂。

3.1 基本使用示例

@Service
@Slf4j
public class OrderService {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    private OrderRepository orderRepository;
    
    public Order createOrder(Order order) {
        // 定义事务属性
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        def.setTimeout(30);
        
        // 获取事务状态
        TransactionStatus status = transactionManager.getTransaction(def);
        
        try {
            // 执行业务逻辑
            Order savedOrder = orderRepository.save(order);
            // 处理订单相关的其他操作
            processOrderDetails(savedOrder);
            
            // 提交事务
            transactionManager.commit(status);
            return savedOrder;
        } catch (Exception e) {
            // 回滚事务
            transactionManager.rollback(status);
            log.error("创建订单失败", e);
            throw new RuntimeException("创建订单失败", e);
        }
    }
}

3.2 嵌套事务示例

@Service
@Slf4j
public class PaymentService {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    private PaymentRepository paymentRepository;
    
    public void processPayment(Payment payment) {
        // 外部事务定义
        DefaultTransactionDefinition outerDef = new DefaultTransactionDefinition();
        outerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus outerStatus = transactionManager.getTransaction(outerDef);
        
        try {
            // 外部事务操作
            paymentRepository.save(payment);
            
            // 内部事务定义
            DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
            innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
            TransactionStatus innerStatus = transactionManager.getTransaction(innerDef);
            
            try {
                // 执行内部事务操作
                processPaymentDetails(payment);
                transactionManager.commit(innerStatus);
            } catch (Exception e) {
                // 回滚内部事务
                transactionManager.rollback(innerStatus);
                log.error("支付详情处理失败", e);
                throw e;
            }
            
            // 提交外部事务
            transactionManager.commit(outerStatus);
        } catch (Exception e) {
            // 回滚外部事务
            transactionManager.rollback(outerStatus);
            log.error("支付处理失败", e);
            throw new RuntimeException("支付处理失败", e);
        }
    }
}

4. 事务传播行为

在编程式事务中,我们可以精确控制事务的传播行为:

@Service
public class TransactionPropagationExample {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public void demonstratePropagation() {
        // REQUIRED 传播行为
        TransactionTemplate requiredTemplate = new TransactionTemplate(transactionTemplate);
        requiredTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        
        // REQUIRES_NEW 传播行为
        TransactionTemplate requiresNewTemplate = new TransactionTemplate(transactionTemplate);
        requiresNewTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        
        // 嵌套使用不同的传播行为
        requiredTemplate.execute(outerStatus -> {
            // 外部事务逻辑
            requiresNewTemplate.execute(innerStatus -> {
                // 内部事务逻辑(新的事务)
                return null;
            });
            return null;
        });
    }
}

5. 事务隔离级别

示例展示如何设置不同的事务隔离级别:

@Service
public class TransactionIsolationExample {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    public void demonstrateIsolation() {
        // 读已提交隔离级别
        DefaultTransactionDefinition readCommittedDef = new DefaultTransactionDefinition();
        readCommittedDef.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        TransactionStatus readCommittedStatus = transactionManager.getTransaction(readCommittedDef);
        
        try {
            // 业务逻辑
            transactionManager.commit(readCommittedStatus);
        } catch (Exception e) {
            transactionManager.rollback(readCommittedStatus);
            throw e;
        }
        
        // 可重复读隔离级别
        DefaultTransactionDefinition repeatableReadDef = new DefaultTransactionDefinition();
        repeatableReadDef.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
        // ... 类似的事务处理逻辑
    }
}

6. 最佳实践

6.1 事务模板封装

创建一个通用的事务处理模板:

@Component
@Slf4j
public class TransactionHelper {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public <T> T executeInTransaction(TransactionCallback<T> action) {
        try {
            return transactionTemplate.execute(action);
        } catch (Exception e) {
            log.error("事务执行失败", e);
            throw new RuntimeException("事务执行失败", e);
        }
    }
    
    public void executeInTransactionWithoutResult(Consumer<TransactionStatus> action) {
        try {
            transactionTemplate.executeWithoutResult(action);
        } catch (Exception e) {
            log.error("事务执行失败", e);
            throw new RuntimeException("事务执行失败", e);
        }
    }
}

// 使用示例
@Service
public class BusinessService {
    
    @Autowired
    private TransactionHelper transactionHelper;
    
    public void doBusiness() {
        transactionHelper.executeInTransactionWithoutResult(status -> {
            // 业务逻辑
        });
    }
}

7. 常见问题与解决方案

7.1 事务超时处理

@Service
public class TimeoutExample {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public void handleTimeout() {
        TransactionTemplate timeoutTemplate = new TransactionTemplate(transactionTemplate);
        timeoutTemplate.setTimeout(5); // 设置5秒超时
        
        try {
            timeoutTemplate.execute(status -> {
                // 可能超时的业务逻辑
                return null;
            });
        } catch (TransactionTimedOutException e) {
            // 处理超时异常
            log.error("事务执行超时", e);
            throw new RuntimeException("事务执行超时", e);
        }
    }
}

7.2 异常处理最佳实践

@Service
public class ExceptionHandlingExample {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public void handleExceptions() {
        try {
            transactionTemplate.execute(status -> {
                try {
                    // 业务逻辑
                    return null;
                } catch (BusinessException e) {
                    // 业务异常,标记回滚
                    status.setRollbackOnly();
                    throw e;
                } catch (Exception e) {
                    // 其他异常,标记回滚
                    status.setRollbackOnly();
                    throw new RuntimeException("未预期的错误", e);
                }
            });
        } catch (Exception e) {
            // 统一异常处理
            handleException(e);
        }
    }
    
    private void handleException(Exception e) {
        if (e instanceof BusinessException) {
            // 处理业务异常
            log.warn("业务异常: {}", e.getMessage());
        } else {
            // 处理系统异常
            log.error("系统异常", e);
        }
        throw e;
    }
}

虽然编程式事务提供了更细粒度的控制,但在大多数情况下,声明式事务(@Transactional)可能是更好的选择。只有在需要特别精细的事务控制时,才考虑使用编程式事务。


http://www.kler.cn/a/445474.html

相关文章:

  • 【我的 PWN 学习手札】IO_FILE 之 stdout任意地址读
  • MySQL第二弹----CRUD
  • 02-18.python入门基础一基础算法
  • 【驱动开发】设备分类、设备号申请和注销,注册和移除字符设备,以及一个基本的内核驱动程序框架代码
  • 软考:系统架构设计师教材笔记(持续更新中)
  • OCR实践-Table-Transformer
  • 2024最新CF罗技鼠标宏
  • 门店全域推广,线下商家营销布局的增量新高地
  • vue.js框架概述
  • 29. 多线程编程
  • 对象的状态变化处理与工厂模式实现
  • UI Automator Viewer操作
  • ASCII码简介以及在php中的使用
  • JavaSE——绘图入门
  • HTTP接口报错详解与解决 200,500,403,408,404
  • 【Pandas】pandas Series shape
  • 【Cadence射频仿真学习笔记】IC设计中电感的分析、建模与绘制(EMX电磁仿真,RFIC-GPT生成无源器件及与cadence的交互)
  • QML 信号与信号处理器程序
  • QScreen在Qt5.15与Qt6.8版本下的区别
  • 将OBJ或GLB文件转换为3DTiles
  • 【数据安全】如何保证其安全
  • 【FFmpeg】万能的视频处理工具使用教程(持续更新)
  • 辅助任务改进社交帖子多模态分类
  • 在Linux上将 `.sh` 脚本、`.jar` 包或其他脚本文件添加到开机自启动
  • uni-app商品搜索页面
  • stm32进硬件错误怎么回事