DataFieldMaxValueIncrementer
是 spring-jdbc
项目中的一个接口。用于在应用中生成连续、自增的序列。可用于 主键ID 、订单号 、流水号 等等。
它基于数据库实现,主要有 2 大子类。
AbstractSequenceMaxValueIncrementer
:用于支持序列(SEQUENCE)的数据库(如 Oracle),使用标准的数据库序列。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-j
和 spring-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
值,前面填充了 9
个 0
,这是因为我们在配置类中设置了 paddingLength
值为 10
,当字符序列长度不足 10
的时候,就会在前面填充 0
。