浅谈Spring事务传播行为实战

浅谈Spring事务传播行为实战

在开发中,我们经常需要处理一些涉及到数据库的事务操作。Spring框架提供了完善的事务管理机制,可以很好的解决事务处理的问题。其中,事务传播行为定义了在方法嵌套调用中如何传播事务。

事务传播行为的定义

Spring中定义了7种事务传播行为:

  • REQUIRED:表示当前方法必须运行在事务内部。如果当前存在事务,则加入该事务中;如果不存在事务,则新建一个事务并加入。
  • SUPPORTS:表示当前方法不需要运行在事务内部。如果当前存在事务,则加入该事务中;如果不存在事务,则直接执行该方法。
  • MANDATORY:表示当前方法必须运行在事务内部。如果当前不存在事务,则抛出异常。
  • REQUIRES_NEW:表示当前方法必须新建一个事务。如果当前存在事务,则挂起该事务并新建一个事务;如果不存在事务,则新建一个事务并加入。
  • NOT_SUPPORTED:表示当前方法不应该运行在事务内部。如果当前存在事务,则挂起该事务;如果不存在事务,则直接执行该方法。
  • NEVER:表示当前方法不应该运行在事务内部。如果当前存在事务,则抛出异常;如果不存在事务,则直接执行该方法。
  • NESTED:表示当前方法必须运行在一个已经存在的事务中,但该事务可以由外部事务管理器创建一个内嵌事务或加入内嵌事务中,外部事务中出现异常会导致所有嵌套的事务都回滚,而内部事务中出现异常仅会影响内部事务的数据。

事务传播行为的选型

在选择合适的事务传播行为时,需要根据实际业务需求来决定,关键要考虑以下几个因素:

  • 配置中的优先级最高。
  • 调用者是否需要始终在同一事务中执行。
  • 如果当前事务不存在,是要发起一个新的事务,还是希望整个方法都在非事务环境下执行。
  • 如果当前事务存在,是否可以共享事务,还是希望开启一个新的事务。
  • 如果当前事务存在,是否希望为某一段代码单独开启一个新的独立事务。

实战示例一

假设有这么一个需求:在处理A账户的转账操作时,需要调用另一个服务对B账户进行入账操作。此时,如果转账操作发生异常,我们希望B账户的入账操作也回滚,如果入账操作发生异常,则希望转账操作不受影响。这时,我们可以使用REQUIRES_NEW传播行为。当转账方法调用B账户的入账方法时,开启一个新的事务,这样如果B账户的入账方法出现异常,只会影响到新开启的事务,而不会影响到之前的转账操作。

示例代码如下:

@Service
public class AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void transfer(String from, String to, BigDecimal amount) throws Exception {
        // A账户扣款
        AccountDTO accountDTO = accountMapper.selectByUserId(from);
        if (accountDTO.getBalance().compareTo(amount) < 0) {
            throw new Exception("余额不足");
        }
        accountMapper.updateBalance(from, accountDTO.getBalance().subtract(amount));

        // 调用B账户入账服务
        try {
            insertB(from, to, amount);
        } catch (Exception e) {
            throw new Exception("B账户入账失败!");
        }

        // 打印转账详情
        System.out.println(from + " 转 " + to + " " + amount + " 元");
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void insertB(String from, String to, BigDecimal amount) throws Exception {
        // B账户入账
        AccountDTO accountDTO = accountMapper.selectByUserId(to);
        accountMapper.updateBalance(to, accountDTO.getBalance().add(amount));

        // 打印入账详情
        System.out.println(to + " 入账 " + amount + " 元");
    }

}

实战示例二

假设有这么一个需求:开发一个秒杀服务,在秒杀活动开始后,用户只有30分钟的时间内支付,否则订单自动取消。此时,我们希望调用外部支付接口,并检查支付结果,如果支付成功,则提交订单,否则取消订单。但是,在检查支付结果和提交订单之间,可能存在多个线程同时进行支付,这时需要避免并发冲突。此时,我们可以使用NESTED传播行为。在检查支付结果和提交订单之间,我们开启一个嵌套事务,这样如果支付结果检查出错,只会回滚该事务,而不会影响整个订单事务的提交。

示例代码如下:

@Service
public class SeckillService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private PaymentService paymentService;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void createOrder(String orderId) throws Exception {
        // 创建订单
        orderMapper.insert(orderId, new Date());

        // 调用支付接口
        boolean success = paymentService.pay(orderId);
        if (success) {
            // 提交订单
            try {
                submitOrder(orderId);
            } catch (Exception e) {
                throw new Exception("提交订单失败!");
            }
        } else {
            // 取消订单
            cancelOrder(orderId);
        }
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
    public void submitOrder(String orderId) throws Exception {
        // 检查库存
        if (checkInventory(orderId)) {
            // 提交订单
            orderMapper.submit(orderId);
        } else {
            throw new Exception("库存不足!");
        }
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
    public void cancelOrder(String orderId) throws Exception {
        // 取消订单
        orderMapper.cancel(orderId);
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈Spring事务传播行为实战 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Java日期工具类DateUtils实例详解

    Java日期工具类DateUtils实例详解 什么是DateUtils DateUtils是Apache Commons Lang库提供的一个日期工具类,可以用来更加方便地操作日期和时间。 DateUtils的常用功能 解析字符串到日期对象 import org.apache.commons.lang3.time.DateUtils; public clas…

    Java 2023年5月20日
    00
  • java单点登录(SSO)的实现

    下面我将详细讲解Java单点登录(SSO)的实现攻略,主要分为以下几个步骤: 步骤一:准备工作 我们需要准备以下工具和环境: JDK 1.8或以上版本 Maven 3.0或以上版本 Servlet容器,如Tomcat或Jetty Spring Boot 2.0或以上版本 步骤二:配置SSO服务器和客户端 配置SSO服务器我们需要在SSO服务器上做以下配置: …

    Java 2023年5月18日
    00
  • SpringBoot配置的加载流程详细分析

    Spring Boot配置的加载流程详细分析 Spring Boot是一个流行的Java框架,可以帮助开发人员快速构建和部署应用程序。在Spring Boot中,配置文件是非常重要的一部分,它们可以帮助我们配置应用程序的各种属性和行为。在本文中,我们将详细讲解Spring Boot配置的加载流程。 配置文件的加载顺序 Spring Boot支持多种类型的配置…

    Java 2023年5月15日
    00
  • java计算两个时间相差天数的方法汇总

    标题:Java计算两个时间相差天数的方法汇总 当我们需要计算两个日期之间相差的天数时,可以通过Java标准库提供的日期时间类来实现。下面将介绍Java计算两个时间相差天数的方法,包括两个示例。 方法一:使用Duration类 Java 8引入了Duration类,用于表示两个时间点之间的时间差,包括秒和纳秒。我们可以使用Duration.between()方…

    Java 2023年5月20日
    00
  • JSP+Ajax 添加、删除多选框

    下面是关于“JSP+Ajax 添加、删除多选框”的攻略。 什么是JSP+Ajax 添加、删除多选框 在 JSP 页面中,我们可以使用多选框来实现批量操作功能。但是,如果想要实现添加、删除选项的功能,通常需要使用 JavaScript 或 JQuery 等客户端脚本。这种方式需要刷新页面才能看到结果,用户体验不好。 而使用 Ajax 技术,则可以通过后台动态更…

    Java 2023年6月15日
    00
  • ColdFusionMX 编程指南 ColdFusionMX编程入门

    首先,需要明确“ColdFusionMX 编程指南 ColdFusionMX编程入门”是一本有关ColdFusionMX编程的入门书籍,其中包含了关于ColdFusion应用程序、变量、函数和流程控制等方面的基本知识和实例,适合初学者阅读学习。 一、阅读方式 1.阅读顺序:建议按照书本的章节顺序阅读,因为每个章节的内容都是有关联的。 2.实践方法:书中的实例…

    Java 2023年6月15日
    00
  • Spring AOP切面解决数据库读写分离实例详解

    下面是完整的攻略: 简介 在基于Spring框架进行开发时,为了提高数据库的读写性能,可以将读写操作分别分配到不同的数据库中,这就是数据库读写分离。Spring框架提供了AOP编程,可以把业务逻辑和数据库操作分开,使得业务逻辑更加专注,减少代码的耦合度。本文基于Spring AOP切面,详细演示实现数据库读写分离的过程。 准备工作 一、配置依赖 在pom.x…

    Java 2023年6月15日
    00
  • 基于javaMybatis存进时间戳的问题

    那我来详细讲解一下关于“基于Java Mybatis存进时间戳的问题”的攻略。 问题背景 在使用Java Mybatis框架进行MySQL数据库操作时,我们有时需要将时间信息存储为时间戳(长整型),然后进行操作。但在实际操作中,我们有可能遇到时间戳值存储不对的问题,导致数据不正确。 解决方案 方案1:使用注解方式进行时间戳的映射 在Mybatis的实体映射中…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部