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
。