详解Springboot事务管理

关于"详解Springboot事务管理"的攻略,我可以给出以下的完整解析:

什么是事务管理

事务(Transaction)是指作为一个不可分割的工作单位所需要执行的一系列操作,这些操作要么全部都执行成功,要么全部都执行失败。对于一些需要多步操作的业务中,我们需要保证其中的每一步都可以正确执行,并且在其中任何一步出错的情况下,都可以撤回所有操作以保证数据的一致性。

事务管理就是针对这种业务场景,进行的一种统一的事务处理机制,通过某种方式,能够确保整个事务的原子性、一致性以及隔离性和持久性。

在Spring框架中,为了支持事务,提供了一种事务操作的管理机制。当我们配置了Spring的事务管理后,在开启事务的情况下,Spring会自动创建一个事务管理器,并为每一个事务绑定一个单独的数据库连接。在操作数据库过程中,如果其中有任何一步执行失败,整个事务都会回滚,确保数据的一致性。

好了,了解了什么是事务管理,接下来我们来看看如何在Springboot中进行配置,实现一个基本的事务案例。

Springboot事务管理配置

在Springboot应用的pom文件中,需要导入以下的对应的依赖项

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--添加事务支持-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!--添加MySQL支持-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

配置文件:application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&autoReconnect=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=trace

这里我们配置了连接到本地 mysql 数据库,在 application.properties 文件中,指定了数据库连接信息和用户名密码。并且为了使JPA与数据库表进行同步,配置了JPA的 hibernate.ddl-auto 属性。

除此之外,在依赖项中,需要添加 spring-boot-starter-data-jpa , 它提供了数据库操作的事务支持。

示例一:转账处理

考虑这样一个业务场景,一个应用中涉及到了转账操作。其中涉及到了两个数据表, account 表表示账户信息,内含列 id、name 和 balance;transfer_log 表表示转账流程信息,是一个记录转账历史的表,内含列 id、out_account、in_account 和 money 。那么要在不同转账户之间进行转账的操作,我们肯定需要管理它的事务,即将它的转账操作封装到一个事务中,保证在转账出现异常时也能保证数据的一致性。

我们先看一下account表的定义,这里只列出了关键字段,数据表结构如下

CREATE TABLE `account` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '自动编号',
    `name` VARCHAR(50) DEFAULT NULL COMMENT '名称',
    `balance` DECIMAL(20,2) DEFAULT NULL COMMENT '余额',
    PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

定义transfer_log表的定义,数据表结构如下

CREATE TABLE `transfer_log` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '自动编号',
    `out_account` INT(11) NOT NULL COMMENT '转出账户',
    `in_account` INT(11) NOT NULL COMMENT '转入账户',
    `money` DECIMAL(10,2) NOT NULL COMMENT '转账金额',
    PRIMARY KEY (`id`),
) ENGINE=INNODB DEFAULT CHARSET=utf8;

上述代码中,transfer_log中的 out_account、in_account 字段需要赋值账户表account中的id,即关联查询。

针对转账场景下的事务管理,下面我们提供一个演示程序:

@Service
public class TransferService {

    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private TransferLogRepository transferLogRepository;

    /**
     * 转账
     * @param fromUser
     * @param toUser
     * @param money
     * @throws ServiceException 转账异常
     */
    @Transactional(rollbackFor = ServiceException.class)
    public void transfer(String fromUser, String toUser, Double money) throws ServiceException {
        Account fromAccount = accountRepository.findByUsername(fromUser);
        Account toAccount = accountRepository.findByUsername(toUser);
        if(fromAccount.getBalance() < money){
            throw new ServiceException("账户余额不足");
        }
        fromAccount.setBalance(fromAccount.getBalance() - money);
        toAccount.setBalance(toAccount.getBalance() + money);
        accountRepository.save(fromAccount);
        accountRepository.save(toAccount);

        TransferLog log = new TransferLog();
        log.setOutAccount(fromAccount.getId());
        log.setInAccount(toAccount.getId());
        log.setMoney(money);
        transferLogRepository.save(log);
    }
}

这里具体说明一下。

首先将 AccountRepository 和 TransferLogRepository 作为依赖项,因为涉及到数据库操作,我们需要配置数据的查询和保存方式。这两个类分别是用来对应account和transfer_log两张表的。

再看以下@Transactional注解,这个注释在这里保证了整个转账操作的执行序列,如果其中任何一步发生了错误,那么整个过程将自动回滚,每步的操作都将撤回,以确保数据的一致性。

在进行转账操作时,需要查询出相关账户信息,若出现转账失败的情况,则通过throw new ServiceException(...) 抛出异常,会被上面@Transactional中的rollbackFor = ServiceException.class截获。并将异常信息记录到日志中。

在转账操作都执行完毕之后,我们会在transfer_log表中,增加一条记录,以便于我们后续的查询。

No.2也是我们在实际业务场景中常常遇到的需求:同时对多张表进行事务管理。接下来我们快速了解一下这个业务需求并提供代码示例。

示例2:订单以及订单详情记录

在实际的业务场景中,经常涉及到多张表之间的联动操作、数据交互,如下这辑种情况:

  • 创建一张订单表 order_info,记录订单基础信息
  • 创建一张订单详情表 detail_info,记录订单明细信息
  • 在对应订单明细页面中,用户可以添加多条明细记录,每条记录都要持久化到detail_info表中并且记录到order_info表中。

为了高效地完成这一系列操作我们需要使用到 Springboot的事务管理机制来确保数据的一致性、隔离性和原子性,确保当任何一步操作失败时,被整个事务自动回滚。

代码实现中,我们通过新增一个 order_info 的记录,并将其生成的主键作为 detail_info 中的外键关联起来,我们来看以下两个 Repository 的代码。

order_info 表:

CREATE TABLE `order_info` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '自动编号',
    `price` DECIMAL(10,2) NOT NULL COMMENT '订单总价',
    PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

detail_info 表:

CREATE TABLE `detail_info` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '自动编号',
    `order_id` INT(11) NOT NULL COMMENT '对应订单编号',
    `detail` CHAR(20) NOT NULL COMMENT '订单详情',
    PRIMARY KEY (`id`),
    KEY `fk_order_id` (`order_id`),
    CONSTRAINT `fk_order_id` FOREIGN KEY (`order_id`) REFERENCES `order_info` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

上面的代码中,detail_info的 order_id 字段和order_info表的主键相连。主键[id]与外键[order_id]形成了主外键约束。

使用Springboot事务管理机制,我们只需要通过@Transactional注释,简单地对方法进行标记,就可以确保整个过程的原子性。

我们看一下订单处理服务类:

@Service
public class OrderService {

    @Autowired
    OrderRepository orderRepository;

    @Autowired
    DetailRepository detailRepository;

    @Transactional(rollbackFor = ServiceException.class)
    public void saveOrder(OrderInfo order, List<DetailInfo> detailList) throws ServiceException {
        order = orderRepository.save(order);
        int orderId = order.getId();
        Iterator ftr = detailList.iterator();

        while(ftr.hasNext()) {
            DetailInfo detail = (DetailInfo)ftr.next();
            detail.setOrderId(orderId);
            detailRepository.save(detail);
        }

    }
}

这里,我们注入 OrderRepository 和 DetailRepository ,并且使用 @Transactional 这个注释,对整个方法进行事务支持。在操作的过程中,保证业务的完整性,同时也消除了中间出现的任何问题。

至此,我们已经对 “详解Springboot事务管理”的内容进行了完整的讲解。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Springboot事务管理 - Python技术站

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

相关文章

  • Java基于外观模式实现美食天下食谱功能实例详解

    Java基于外观模式实现美食天下食谱功能实例详解 什么是外观模式? 外观模式(Facade Pattern)是一种结构型设计模式,它为复杂的子系统提供了简单的接口,隐藏了子系统的复杂性,并将用户与子系统的实现分离开来。外观模式提供了一种更简单、更方便的方式来使用子系统,降低了使用成本。 美食天下食谱功能实例说明 假设我们在设计一个美食网站,需要实现一个食谱功…

    Java 2023年5月19日
    00
  • 支持Java 14!Java开发工具IntelliJ IDEA 2020.1稳定版发布

    下面是关于“支持Java 14!Java开发工具IntelliJ IDEA 2020.1稳定版发布”的详细攻略: 什么是IntelliJ IDEA? IntelliJ IDEA是一款由JetBrains开发的Java和其他编程语言的集成开发环境(IDE)。它提供了强大的功能,如代码智能提示、错误检查、重构、版本控制等等,同时也支持许多其他开发技术和框架。In…

    Java 2023年5月19日
    00
  • Java中的局部内部类是什么?

    Java中的局部内部类是一个定义在方法或作用域内部的类,它只能在它所在的方法或作用域内使用,并且不能声明为public、protected和private等访问修饰符。局部内部类与成员内部类不同,它是嵌套在方法中的内部类,因此它只能访问它所在的方法中的final局部变量,而不能访问非final的局部变量。 下面我们来看两个实例来更具体的理解局部内部类: 示例…

    Java 2023年4月27日
    00
  • 详解springmvc 中controller与jsp传值

    详解SpringMVC中Controller与JSP传值 在SpringMVC中,Controller与JSP之间的数据传递是非常常见的操作。本文将详细讲解如何在SpringMVC中实现Controller与JSP之间的数据传递,并提供两个示例说明。 实现步骤 下面是实现Controller与JSP之间的数据传递的详细步骤: 步骤一:创建Maven项目 首先…

    Java 2023年5月17日
    00
  • java下使用kaptcha生成验证码

    生成验证码常常用于网站的用户登录、注册和重置密码等操作中,可以有效地防止恶意攻击和密码爆破。在Java语言中,可以使用kaptcha库来快速生成验证码。 下面是使用kaptcha生成验证码的步骤和示例: 步骤1:添加依赖 在pom.xml中添加以下依赖,表示使用kaptcha的生成验证码功能: <dependency> <groupId&g…

    Java 2023年6月15日
    00
  • Java读写文件方法总结(推荐)

    Java读写文件方法总结(推荐) Java是一个非常强大的编程语言,用于读写文件时也同样灵活方便。下面是基于Java读写文件的方法总结。 读取文件 1. 使用InputStreamReader类 以下是使用InputStreamReader类读取文件的方法: public static void readWithInputStreamReader(Strin…

    Java 2023年5月20日
    00
  • JSP迅速入门

    以下是JSP迅速入门的完整攻略: JSP介绍 Java服务器页面(Java Server Pages,JSP)是一种动态网页技术,JSP和PHP、ASP相似,JSP由HTML、Java代码、JSP标签和表达式组成,它允许Java代码和命令直接插入HTML页面中。 JSP环境搭建 要使用JSP技术,需要一台运行Web应用程序的Web服务器,比如Tomcat、J…

    Java 2023年5月20日
    00
  • Spring MVC处理方法返回值过程解析

    下面我来详细讲解一下“Spring MVC处理方法返回值过程解析”的完整攻略。 什么是Spring MVC处理方法返回值过程? Spring MVC是基于MVC结构的开发框架,其中的控制器(Controller)负责处理用户请求并返回响应结果。在Spring MVC的控制器中,方法的返回值封装成一个ModelAndView对象,其中包含了视图名、数据模型和状…

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