详解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搞定汉诺塔 汉诺塔是一种经典的递归算法题目,许多编程语言课程书籍都会在最初的课程中讲述它。Java 作为行业中使用最广泛的编程语言之一,自然也有自己实现汉诺塔的方法。在本篇攻略中,我们将一步步讲解如何使用 Java 代码实现汉诺塔算法。 算法原理 汉诺塔问题的递推公式如下: 在只有一个盘子时,将其直接移动到目标柱子上。 在有n (n &g…

    Java 2023年5月23日
    00
  • Java字符串写入文件三种方式的实现

    【Java字符串写入文件三种方式的实现】 写入文件是我们在Java程序开发中常见的任务之一。而字符串写入文件则更为常见,因为我们需要保存或输出的许多数据都是由字符串组成的。在这个攻略中,我将向你展示如何使用三种不同的方式在Java中将字符串写入文件。 方式一:使用字符流写入文件 使用字符流写入文件并不难,主要分为三步: 创建一个文件输出流。可以使用Java中…

    Java 2023年5月20日
    00
  • 一文读懂Spring Bean的生命周期

    一文读懂Spring Bean的生命周期 Spring是一款非常流行的Java开发框架,支持面向对象编程、IOC和AOP等高级特性,而Spring Bean是其最基本的组成部分。本文将通过详细讲解Spring Bean的生命周期来帮助读者深入理解Spring框架的工作原理。 什么是Spring Bean? Spring Bean是Spring IoC容器中管…

    Java 2023年5月19日
    00
  • Java中使用JWT生成Token进行接口鉴权实现方法

    为了在Java中使用JWT生成Token进行接口鉴权,我们需要以下步骤: 1. 引入依赖 我们需要在项目中引入一个JWT依赖,例如Java JWT(https://github.com/auth0/java-jwt)。 Maven坐标如下: <dependency> <groupId>com.auth0</groupId>…

    Java 2023年5月20日
    00
  • java 如何复制非空对象属性值

    要复制Java对象的非空属性值,可以使用Java自带的BeanUtils.copyProperties方法或Apache Commons BeanUtils框架中的copyProperties方法。 下面分别展示使用这两种方法复制Java对象的非空属性值的示例: 使用Java自带的BeanUtils.copyProperties方法 import org.a…

    Java 2023年5月26日
    00
  • Java FileWriter输出换行操作

    下面是关于Java FileWriter输出换行操作的详细讲解: 什么是FileWriter FileWriter 是一个用来写入字符流的便利类。它可以将文本写入到文件中,如果文件不存在则会自动创建。与 FileOutputStream 类似,你可以指定写入数据的文件名和写入数据时是否追加到文件的末尾。 FileWriter 输出换行 在Java中,换行的表…

    Java 2023年5月26日
    00
  • Java泛型与注解全面分析讲解

    Java泛型与注解是Java编程中非常重要的特性。下面我来详细讲解“Java泛型与注解全面分析讲解”的完整攻略。 一、Java泛型 1. 什么是Java泛型 Java泛型是指,当一个类、接口、方法中需要支持多种数据类型的时候,使用泛型可以让代码更加简洁、易读、健壮性更好。Java泛型分为泛型类、泛型接口和泛型方法。Java泛型使用中需要注意的是类型擦除和通配…

    Java 2023年5月26日
    00
  • 史上最全面的Spring Boot配置文件深入讲解

    史上最全面的Spring Boot配置文件深入讲解 Spring Boot是一个快速构建企业级应用程序的框架,它允许我们通过配置文件来快速配置和启动应用程序。在Spring Boot中,我们可以使用application.properties或application.yml等配置文件来配置应用程序的属性,以满足我们的需求。本文将深入讲解Spring Boot…

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