51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

在 Spring Boot 中使用 DataFieldMaxValueIncrementer 获取自增序列

DataFieldMaxValueIncrementerspring-jdbc 项目中的一个接口。用于在应用中生成连续、自增的序列。可用于 主键ID订单号流水号 等等。

它基于数据库实现,主要有 2 大子类。

  1. AbstractSequenceMaxValueIncrementer:用于支持序列(SEQUENCE)的数据库(如 Oracle),使用标准的数据库序列。
  2. AbstractColumnMaxValueIncrementer:用于不支持序列的数据库(如,MYSQL),使用一张表来模拟。

spring-jdbc 已经为当前流行的关系型数据库提供了具体的实现,类体系结构如下:

DataFieldMaxValueIncrementer
    |-AbstractDataFieldMaxValueIncrementer
        |-AbstractSequenceMaxValueIncrementer
            |-OracleSequenceMaxValueIncrementer # Oracle 数据库
            |-PostgresSequenceMaxValueIncrementer # Postgres 数据库
            |-SqlServerSequenceMaxValueIncrementer # SqlServer 数据库
            |- ...      # 还有一些其他的,这里忽略
        |-AbstractColumnMaxValueIncrementer
            |-MySQLMaxValueIncrementer # MYSQL 数据库

DataFieldMaxValueIncrementer {#datafieldmaxvalueincrementer}

DataFieldMaxValueIncrementer 接口只有 3 个方法,很简单。

public interface DataFieldMaxValueIncrementer {
    int nextIntValue() throws DataAccessException;
    long nextLongValue() throws DataAccessException;
    String nextStringValue() throws DataAccessException;
}
  • nextIntValue:以 int 类型返回下一个序列。
  • nextLongValue:以 long 类型返回下一个序列。
  • nextStringValue:以 String 类型返回下一个序列。

使用 MySQLMaxValueIncrementer {#使用-mysqlmaxvalueincrementer}

本文以 MySQLMaxValueIncrementer 为例(毕竟 MYSQL 最流行)。

软件版本如下:

  • Spring Boot:3.0.3
  • MySQL:8.0.0

创建 Spring Boot 项目 {#创建-spring-boot-项目}

添加 MySQL 驱动 mysql-connector-jspring-boot-starter-jdbc 依赖。

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

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
</dependency>

配置数据库 {#配置数据库}

在配置文件中(application.properties / application.yaml),配置好基础的数据源信息。

spring:
  datasource:
    # 数据源实现
    type: com.zaxxer.hikari.HikariDataSource
    # 驱动类
    driver-class-name: com.mysql.cj.jdbc.Driver
    # URL
    url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&allowMultiQueries=true
    # 用户名
    username: root
    # 密码
    password: root

创建配置类 {#创建配置类}

创建 @Configuration 配置类,实例化 MySQLMaxValueIncrementer 对象,并且注册为 Bean。

package cn.springdoc.demo.configuration;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer;

@Configuration
public class MySQLMaxValueIncrementerConfiguration {

    @Bean
    public MySQLMaxValueIncrementer mySQLMaxValueIncrementer(DataSource dataSource) {
        MySQLMaxValueIncrementer mySQLMaxValueIncrementer = new MySQLMaxValueIncrementer();
        /**
         * 数据源
         */
        mySQLMaxValueIncrementer.setDataSource(dataSource);
        /**
         * 维护序列的表名
         */
        mySQLMaxValueIncrementer.setIncrementerName("T_SEQUENCE");
        /**
         * 序列表中的列名称
         */
        mySQLMaxValueIncrementer.setColumnName("val");
        /**
         * 字符串结果的填充长度,不足长度会在前面填充0,默认为 0
         */
        mySQLMaxValueIncrementer.setPaddingLength(10);
        /**
         * 是否每次获取序列都是使用新的数据库连接,默认为true
         */
        mySQLMaxValueIncrementer.setUseNewConnection(false);
        /**
         * 设置缓存序列的个数,当内存中的序列用完后,会将一次性生成 cacheSize 个序列缓存到内存。
         */
        mySQLMaxValueIncrementer.setCacheSize(1);

        return mySQLMaxValueIncrementer;
    }
    }

通过 @Bean 方法参数注入 Datasource 对象,MySQLMaxValueIncrementer 依赖它来获取数据库连接,进行查询操作。其他的方法都很简单,在注释中都有说明。

最后,我们需要手动在数据库中创建本例中模拟序列的表和列,如下:

CREATE TABLE `t_sequence` (
  `val` bigint unsigned NOT NULL,
  PRIMARY KEY (`val`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

然后初始化唯一的一条记录,设置自增列的初始化值:

INSERT INTO `t_sequence`
(val)
VALUES(0);

测试 {#测试}

创建测试类:

package cn.springdoc.demo.test;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;


@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {

    static final Logger log = LoggerFactory.getLogger(DemoApplicationTests.class);

    // 注入 DataFieldMaxValueIncrementer
    @Autowired
    DataFieldMaxValueIncrementer dataFieldMaxValueIncrementer;

    @Test
    public void test() throws Exception {
        
        int intVal = this.dataFieldMaxValueIncrementer.nextIntValue();
        long longVal = this.dataFieldMaxValueIncrementer.nextLongValue();
        String stringVal = this.dataFieldMaxValueIncrementer.nextStringValue();
        
        log.info("next = {}", intVal);
        log.info("next = {}", longVal);
        log.info("next = {}", stringVal);
    }
}

在测试类中注入 DataFieldMaxValueIncrementer 接口,分别调用了它的三个序列生成方法。

执行测试,控制台输出的日志如下:

[           main] c.s.demo.test.DemoApplicationTests       : next = 1
[           main] c.s.demo.test.DemoApplicationTests       : next = 2
[           main] c.s.demo.test.DemoApplicationTests       : next = 0000000003

一切OK,这正是我们需要的自增且连续的序列。

注意 stringVal 值,前面填充了 90,这是因为我们在配置类中设置了 paddingLength 值为 10,当字符序列长度不足 10 的时候,就会在前面填充 0

赞(0)
未经允许不得转载:工具盒子 » 在 Spring Boot 中使用 DataFieldMaxValueIncrementer 获取自增序列