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

SpringBoot事务管理(四)

记录几条SpringBoot事务管理中踩过的坑及解决办法:

1. 自调用问题

问题描述

在同一个类中,一个非事务方法调用另一个有 @Transactional 注解的事务方法,事务不会生效。因为 Spring 的事务管理是基于 AOP 代理实现的,自调用时不会经过代理对象,所以事务注解不起作用。

示例代码
@Service
public class UserService {

    public void nonTransactionalMethod() {
        // 调用事务方法
        this.transactionalMethod(); 
    }

    @Transactional
    public void transactionalMethod() {
        // 数据库操作
    }
}
解决办法

可以通过注入自身的代理对象来解决自调用问题,或者将事务方法提取到另一个服务类中。

@Service
public class UserService {

    @Autowired
    private UserService self;

    public void nonTransactionalMethod() {
        // 通过代理对象调用事务方法
        self.transactionalMethod(); 
    }

    @Transactional
    public void transactionalMethod() {
        // 数据库操作
    }
}

2. 异常捕获问题

问题描述

在事务方法中捕获了异常但没有重新抛出,会导致事务不会回滚。因为 Spring 默认只对未检查异常(如 RuntimeException 及其子类)进行回滚,捕获异常后没有抛出,Spring 无法感知到异常,就不会触发回滚机制。

示例代码
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void saveUser(User user) {
        try {
            userRepository.save(user);
            // 模拟异常
            int result = 1 / 0; 
        } catch (Exception e) {
            // 捕获异常但未重新抛出
            e.printStackTrace(); 
        }
    }
}
解决办法

在捕获异常后,根据业务需求重新抛出未检查异常,或者在 @Transactional 注解中指定需要回滚的异常类型。

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(rollbackFor = Exception.class)
    public void saveUser(User user) {
        try {
            userRepository.save(user);
            // 模拟异常
            int result = 1 / 0; 
        } catch (Exception e) {
            // 重新抛出异常
            throw new RuntimeException(e); 
        }
    }
}

3. 事务传播行为误用

问题描述

在嵌套事务中,如果错误地使用了事务传播行为,可能会导致事务管理不符合预期。例如,在需要独立事务的场景下使用了 REQUIRED 传播行为,会使内层事务加入到外层事务中,当外层事务回滚时,内层事务也会回滚。

示例代码
@Service
public class OrderService {

    @Autowired
    private PaymentService paymentService;

    @Transactional
    public void createOrder(Order order) {
        // 创建订单
        // 调用支付服务
        paymentService.processPayment(order); 
    }
}

@Service
public class PaymentService {

    @Transactional(propagation = Propagation.REQUIRED)
    public void processPayment(Order order) {
        // 处理支付
    }
}
解决办法

根据业务需求选择合适的事务传播行为。如果需要独立事务,可以使用 REQUIRES_NEW 传播行为。

@Service
public class PaymentService {

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processPayment(Order order) {
        // 处理支付
    }
}

4. 数据库隔离级别不匹配

问题描述

在不同的数据库和业务场景下,如果使用了不匹配的事务隔离级别,可能会出现数据不一致的问题。例如,在高并发场景下使用了较低的隔离级别,可能会导致脏读、不可重复读和幻读问题。

示例代码
@Service
public class ProductService {

    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public Product getProductById(Long id) {
        // 查询产品信息
        return productRepository.findById(id).orElse(null);
    }
}
解决办法

根据业务需求和数据库特性选择合适的隔离级别。在高并发场景下,为了保证数据一致性,可以使用较高的隔离级别,如 REPEATABLE_READSERIALIZABLE,但要注意可能会影响并发性能。

@Service
public class ProductService {

    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public Product getProductById(Long id) {
        // 查询产品信息
        return productRepository.findById(id).orElse(null);
    }
}

5. 多数据源事务问题

问题描述

在使用多数据源的 Spring Boot 应用中,如果没有正确配置事务管理器,可能会导致事务管理混乱。不同数据源需要不同的事务管理器来管理事务。

解决办法

为每个数据源配置独立的事务管理器,并在 @Transactional 注解中指定使用的事务管理器。

@Configuration
public class DataSourceConfig {

    @Bean(name = "dataSource1")
    public DataSource dataSource1() {
        // 配置数据源 1
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dataSource2")
    public DataSource dataSource2() {
        // 配置数据源 2
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "transactionManager1")
    public PlatformTransactionManager transactionManager1(@Qualifier("dataSource1") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "transactionManager2")
    public PlatformTransactionManager transactionManager2(@Qualifier("dataSource2") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

@Service
public class MultiDataSourceService {

    @Transactional("transactionManager1")
    public void operationOnDataSource1() {
        // 对数据源 1 进行操作
    }

    @Transactional("transactionManager2")
    public void operationOnDataSource2() {
        // 对数据源 2 进行操作
    }
}

相关文章:

  • Faster-Whisper —— 为语音识别加速的利器
  • 283. 移动零
  • 【QT】Qt4 QtWebKit使用教程
  • 数据结构与算法-双指针法
  • Java 大视界 -- 基于 Java 的大数据可视化在城市规划决策支持中的交互设计与应用案例(164)
  • 30-超市进销存管理系统
  • RAG 高效检索利器 打造企业 “规章制度智能体”(ollama + deepseek + langchain + MinerU)
  • 力扣经典算法篇-5-多数元素(哈希统计,排序,摩尔投票法)
  • CES Asia 2025:行业话语权的逐鹿高地
  • 如何利用系统的数据分析能力提高利润额?
  • websocket获取客服端真实ip
  • Linux | I.MX6ULL 终结者底板原理图讲解(5)
  • 最新万能场馆预约系统源码 基于ThinkPHP+UniApp 含图文搭建部署教程
  • Python+新版DeepSeek V3轻松开发Agent
  • Unity跨平台输入系统
  • Doris Streamloader安装教程
  • LeetCode 78.子集
  • 字符函数,日期函数笔记
  • QinQ-端口安全
  • 【54】结构体:结构体指针的内存与通信
  • 厦门做网站的公司/中山排名推广
  • 响应式企业网站建设/nba交易最新消息
  • 哪家购物网站做的好/seo搜索引擎优化就业指导
  • 惠州网站seo收费/北京百度推广优化
  • 女人与黑狗做视频网站/企业查询
  • 最受欢迎的网站开发语言市场有率/北京seo运营推广