初次提交
This commit is contained in:
405
README.md
405
README.md
@@ -1,3 +1,404 @@
|
|||||||
# seq
|
# seq——基于mysql+spring-jdbc的自增序号生成器
|
||||||
|
|
||||||
基于mysql+spring-jdbc的自增序号生成器
|
---
|
||||||
|
|
||||||
|
用于生成全局自增序号,跳过的序号可以回收使用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
|
||||||
|
+ 在项目中放置jar包的地方把seq-1.0.0.jar、seq-1.0.0-sources.jar、seq-1.0.0-pom.xml复制过去
|
||||||
|
+ 在pom.xml中增加以下内容,然后执行maven命令:mvn clean
|
||||||
|
|
||||||
|
```xml
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cdhncy</groupId>
|
||||||
|
<artifactId>seq</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<exclusions>
|
||||||
|
<!-- 如若你项目中有引用spring-jdbc,则需要排除seq的jdbc依赖 -->
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-jdbc</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<!-- 如若你项目中有引用mysql驱动,则需要排除seq的mysql依赖 -->
|
||||||
|
<exclusion>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<!-- 每次执行mvn clean时,自动安装指定的jar包 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-install-plugin</artifactId>
|
||||||
|
<version>2.5</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>install-external</id>
|
||||||
|
<phase>clean</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>install-file</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<!-- ${project.basedir}表示当前项目的根目录 -->
|
||||||
|
<file>${project.basedir}/lib/seq-1.0.0.jar</file>
|
||||||
|
<pomFile>${pom.basedir}/lib/seq-1.0.0-pom.xml</pomFile>
|
||||||
|
<sources>${project.basedir}/lib/seq-1.0.0-sources.jar</sources>
|
||||||
|
<repositoryLayout>default</repositoryLayout>
|
||||||
|
<groupId>com.cdhncy</groupId>
|
||||||
|
<artifactId>seq</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<generatePom>true</generatePom>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</build>
|
||||||
|
```
|
||||||
|
|
||||||
|
+ springboot中配置方式一(优先):直接注入已有jdbcTemplate和transactionTemplate
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.yang.springseq.config;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.config.GeneratorConfig;
|
||||||
|
import com.cdhncy.seq.config.TableConfig;
|
||||||
|
import com.cdhncy.seq.generator.Generator;
|
||||||
|
import com.cdhncy.seq.generator.impl.SequencesGenerator;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于已有的jdbcTemplate和transactionTemplate,一般如果引用了spring的数据库操作,如jpa、mybatis,都可以直接注入
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SeqGeneratorConfig {
|
||||||
|
/**
|
||||||
|
* 注入已有的数据库操作模板
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
/**
|
||||||
|
* 注入已有的事务操作模板
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号表配置类
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public TableConfig tableConfig() {
|
||||||
|
TableConfig tableConfig = new TableConfig();
|
||||||
|
//自定义表名、字段名
|
||||||
|
//tableConfig.setTable("sequences");
|
||||||
|
//tableConfig.setKeyColumn("SEQUENCE_KEY");
|
||||||
|
//tableConfig.setTypeColumn("SEQUENCE_TYPE");
|
||||||
|
//tableConfig.setSeqColumn("SEQUENCE_NEXT_ID");
|
||||||
|
//tableConfig.setCreateTimeColumn("CREATE_TIME");
|
||||||
|
return tableConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号生成器配置类
|
||||||
|
* @param tableConfig 序号表配置类
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public GeneratorConfig generatorConfig(TableConfig tableConfig) {
|
||||||
|
GeneratorConfig generatorConfig = new GeneratorConfig();
|
||||||
|
generatorConfig.setJdbcTemplate(jdbcTemplate);
|
||||||
|
generatorConfig.setTransactionTemplate(transactionTemplate);
|
||||||
|
generatorConfig.setTableConfig(tableConfig);
|
||||||
|
return generatorConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册序号生成器类
|
||||||
|
* @param generatorConfig 序号生成器配置类
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Generator generator(GeneratorConfig generatorConfig) {
|
||||||
|
return new SequencesGenerator(generatorConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
+ springboot中配置方式二:注入已有的dataSource或自行构建dataSource,通过dataSource自动生成jdbcTemplate和transactionTemplate
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.yang.springseq.config;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.config.GeneratorConfig;
|
||||||
|
import com.cdhncy.seq.config.TableConfig;
|
||||||
|
import com.cdhncy.seq.generator.Generator;
|
||||||
|
import com.cdhncy.seq.generator.impl.SequencesGenerator;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注入已有的dataSource或自行构建dataSource,通过dataSource自动生成jdbcTemplate和transactionTemplate
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SeqGeneratorConfig {
|
||||||
|
/**
|
||||||
|
* 注入已有的数据源,果没有,也可以自行构建
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号表配置类
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public TableConfig tableConfig() {
|
||||||
|
TableConfig tableConfig = new TableConfig();
|
||||||
|
//自定义表名、字段名
|
||||||
|
//tableConfig.setTable("sequences");
|
||||||
|
//tableConfig.setKeyColumn("SEQUENCE_KEY");
|
||||||
|
//tableConfig.setTypeColumn("SEQUENCE_TYPE");
|
||||||
|
//tableConfig.setSeqColumn("SEQUENCE_NEXT_ID");
|
||||||
|
//tableConfig.setCreateTimeColumn("CREATE_TIME");
|
||||||
|
return tableConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号生成器配置类
|
||||||
|
* @param tableConfig 序号表配置类
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public GeneratorConfig generatorConfig(TableConfig tableConfig) {
|
||||||
|
GeneratorConfig generatorConfig = new GeneratorConfig();
|
||||||
|
generatorConfig.setDataSource(dataSource);
|
||||||
|
return generatorConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册序号生成器类
|
||||||
|
* @param generatorConfig 序号生成器配置类
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Generator generator(GeneratorConfig generatorConfig) {
|
||||||
|
return new SequencesGenerator(generatorConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
+ 使用:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.yang.springseq.config;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.generator.Generator;
|
||||||
|
import com.cdhncy.seq.po.Sequences;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SeqTestService {
|
||||||
|
@Resource
|
||||||
|
private Generator generator;
|
||||||
|
|
||||||
|
public void test() {
|
||||||
|
//释放未锁定序号,此处测试,因此每次生成前都全部释放,实际使用时,建议通过定时任务,隔天释放。
|
||||||
|
generator.release();
|
||||||
|
|
||||||
|
//释放指定时间范围内的序号。建议使用定时任务,当天释放前天时间段的序号
|
||||||
|
//generator.release(beginDate,endDate);
|
||||||
|
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
//开启多线程进行测试,实际使用时,每个业务中只需要execute()->{}里面的方法,这里是测试多个用户同时使用时是否会重复
|
||||||
|
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100));
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
threadPoolExecutor.execute(() -> {
|
||||||
|
Sequences sequences = generator.generate("SNT", "MISSION");
|
||||||
|
String formattedSeq = generator.format(sequences.getSeq(), 5, "处〔#year#〕10801#seq#");
|
||||||
|
generator.lock(sequences);
|
||||||
|
set.add(formattedSeq);
|
||||||
|
//打印生成的序号
|
||||||
|
System.out.println(formattedSeq);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
threadPoolExecutor.shutdown();
|
||||||
|
while (true) {
|
||||||
|
if (threadPoolExecutor.isTerminated())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
System.out.println("共生成了:" + set.size() + "个");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
TableConfig配置项,通过set方法设置(一般不用改,如果已有相同结构的表,则可以通过这些配置将原数据利用起来):
|
||||||
|
|
||||||
|
| 配置项 | 类型 | 默认值 | 说明 |
|
||||||
|
|------------------|--------|-------------|--------------------|
|
||||||
|
| table | String | sequences | 序号表名称 |
|
||||||
|
| keyColumn | String | key | 序号名称列名,和序号类型组成唯一主键 |
|
||||||
|
| typeColumn | String | type | 序号类型列名,和序号名称组成唯一主键 |
|
||||||
|
| seqColumn | String | seq | 序号值列名,和序号名称组成唯一主键 |
|
||||||
|
| createTimeColumn | String | create_time | 创建时间列名,用于未锁定表排序 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
GeneratorConfig配置项,通过set方法设置
|
||||||
|
|
||||||
|
| 配置项 | 类型 | 默认值 | 说明 |
|
||||||
|
|---------------------|------------------------------------------------------------------|------------------|----------|
|
||||||
|
| dataSource | javax.sql.DataSource | null | 数据源 |
|
||||||
|
| jdbcTemplate | org.springframework.jdbc.core.JdbcTemplate | null | 数据库操作模板 |
|
||||||
|
| transactionTemplate | org.springframework.jdbc.core.JdbcTemplate | null | 事务操作模板 |
|
||||||
|
| transactionManager | org.springframework.jdbc.datasource.DataSourceTransactionManager | null | 事务管理器 |
|
||||||
|
| autoCreate | Boolean | true | 开启自动建表 |
|
||||||
|
| step | Integer | 1 | 序号增加时的步长 |
|
||||||
|
| tableConfig | com.cdhncy.seq.config.TableConfig | TableConfig的默认配置 | 表配置 |
|
||||||
|
|
||||||
|
以上配置中,jdbcTemplate和transactionTemplate优先级最高,如果jdbcTemplate、transactionTemplate、dataSource、transactionManager同时配置,则dataSource和transactionManager无效;
|
||||||
|
进行这几种组合:dataSource+autoCreate+step+tableConfig,jdbcTemplate+transactionTemplate+autoCreate+step+tableConfig,jdbcTemplate+transactionManager+autoCreate+step+tableConfig
|
||||||
|
|
||||||
|
---
|
||||||
|
Generator方法如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.cdhncy.seq.generator;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.po.Sequences;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnlock;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnused;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface Generator {
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的年
|
||||||
|
*/
|
||||||
|
String YEAR = "#year#";
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的月
|
||||||
|
*/
|
||||||
|
String MONTH = "#month#";
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的日
|
||||||
|
*/
|
||||||
|
String DAY = "#day#";
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的格式化后的序号
|
||||||
|
*/
|
||||||
|
String SEQ = "#seq#";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据传入的key和type生成可用的序号对象。
|
||||||
|
* <p/>
|
||||||
|
* 如果根据key和type在{@link Sequences}中找不到记录,说明该组合的序号对象还未初次生成,返回的是seq为step的序号对象,该对象数据会写入到{@link SequencesUnlock}中。
|
||||||
|
* <p/>
|
||||||
|
* 如果根据key和type在{@link Sequences}中找到了记录,且在{@link SequencesUnused}也找到了记录,说明该组合生成的序号有部分未使用,返回的是{@link SequencesUnused}中找到的seq最小的序号对象。同时会将{@link SequencesUnused}中找到的seq最小的记录删除,然后写入到{@link SequencesUnlock}中。
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @param key 数据字典中的编码
|
||||||
|
* @param type 序号类型
|
||||||
|
* @return 可用的序号对象
|
||||||
|
*/
|
||||||
|
Sequences generate(String key, String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回根据{@link #generate(String, String)}得到的序号对象,补零后的序号字符串
|
||||||
|
* <p/>
|
||||||
|
* 如生成的为3,而minLength为5,则返回的是00003
|
||||||
|
*
|
||||||
|
* @param key 数据字典中的编码
|
||||||
|
* @param type 序号类型
|
||||||
|
* @param minLength 序号数字最小长度
|
||||||
|
* @return 补零后的字符串
|
||||||
|
*/
|
||||||
|
String generate(String key, String type, Integer minLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将生成的序号对象格式化为指定格式
|
||||||
|
* <p/>
|
||||||
|
* pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量
|
||||||
|
* <p/>
|
||||||
|
* seq为1,minLength为4,pattern为#year##month##day#6#seq#,则会格式化为2022013060001。此序号含义如下:
|
||||||
|
* <p/>
|
||||||
|
* 序号格式:[年][月][日][固定6开头][序号1,最小位数为4位,不足4位则补零]
|
||||||
|
*
|
||||||
|
* @param seq 需要格式化的序号
|
||||||
|
* @param minLength 序号最小长度,不足的会补零
|
||||||
|
* @param pattern 格式
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
String format(Long seq, Integer minLength, String pattern);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将生成的序号对象格式化为指定格式
|
||||||
|
* <p/>
|
||||||
|
* pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量
|
||||||
|
* <p/>
|
||||||
|
* seq为1,start为6,minLength为4,pattern为#year##month##day##seq#,则会格式化为2022013060001。此序号含义如下:
|
||||||
|
* <p/>
|
||||||
|
* 序号格式:[年][月][日][固定6开头][序号1,最小位数为4位,不足4位则补零]
|
||||||
|
*
|
||||||
|
* @param seq 需要格式化的序号
|
||||||
|
* @param start 序号格式化后以什么字符串开头
|
||||||
|
* @param minLength 序号最小长度,不足的会补零
|
||||||
|
* @param pattern 格式
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
String format(Long seq, String start, Integer minLength, String pattern);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 锁定指定序号,在序号生成后,调用该序号的逻辑完成后需要执行此方法
|
||||||
|
* <p/>
|
||||||
|
* 如办理案件时,先调用{@link #generate(String, String)}或者{@link #generate(String, String, Integer)}生成了序号,之后对案件进行了入库,如果入库完毕,则将该序号锁定,说明这个序号已被使用
|
||||||
|
* <p/>
|
||||||
|
* 注意,此处的锁定非数据库中锁定,而是{@link SequencesUnused}和{@link SequencesUnlock}中均不存在key、type、seq相同的记录视为锁定。因此此处实际是把这两个表中的记录均删除了
|
||||||
|
*
|
||||||
|
* @param sequences 需要锁定的序号
|
||||||
|
* @return 锁定结果
|
||||||
|
*/
|
||||||
|
boolean lock(Sequences sequences);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放所有未使用的序号
|
||||||
|
* <p/>
|
||||||
|
* {@link SequencesUnlock}中未通过{@link #lock(Sequences)}方法锁定的序号会一直存在,调用此方法会将里面的所有序号都移动到{@link SequencesUnused}中,下次生成序号时优先从{@link SequencesUnused}获取。
|
||||||
|
*/
|
||||||
|
void release();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放指定时间段内未使用的序号
|
||||||
|
* <p/>
|
||||||
|
* {@link SequencesUnlock}中未通过{@link #lock(Sequences)}方法锁定的序号会一直存在,调用此方法会将里面的所有序号都移动到{@link SequencesUnused}中,下次生成序号时优先从{@link SequencesUnused}获取。
|
||||||
|
*
|
||||||
|
* @param begin 开始时间
|
||||||
|
* @param end 结束时间
|
||||||
|
*/
|
||||||
|
void release(Date begin, Date end);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
57
pom.xml
Normal file
57
pom.xml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.cdhncy</groupId>
|
||||||
|
<artifactId>seq</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>seq</name>
|
||||||
|
<description>seq</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-jdbc</artifactId>
|
||||||
|
<version>5.3.15</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>8.0.28</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>8</source>
|
||||||
|
<target>8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-sources</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
115
src/main/java/com/cdhncy/seq/config/GeneratorConfig.java
Normal file
115
src/main/java/com/cdhncy/seq/config/GeneratorConfig.java
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package com.cdhncy.seq.config;
|
||||||
|
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成器配置
|
||||||
|
*
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class GeneratorConfig {
|
||||||
|
/**
|
||||||
|
* 数据源
|
||||||
|
*/
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据库操作模板
|
||||||
|
*/
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务处理模板
|
||||||
|
*/
|
||||||
|
private TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务管理器
|
||||||
|
*/
|
||||||
|
private DataSourceTransactionManager transactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动创建表
|
||||||
|
*/
|
||||||
|
private Boolean autoCreate = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号每次增加的步长
|
||||||
|
*/
|
||||||
|
private Integer step = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表和字段配置
|
||||||
|
*/
|
||||||
|
private TableConfig tableConfig = new TableConfig();
|
||||||
|
|
||||||
|
public GeneratorConfig() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratorConfig(DataSource dataSource) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataSource getDataSource() {
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataSource(DataSource dataSource) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JdbcTemplate getJdbcTemplate() {
|
||||||
|
return jdbcTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
|
||||||
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransactionTemplate getTransactionTemplate() {
|
||||||
|
return transactionTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
|
||||||
|
this.transactionTemplate = transactionTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataSourceTransactionManager getTransactionManager() {
|
||||||
|
return transactionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionManager(DataSourceTransactionManager transactionManager) {
|
||||||
|
this.transactionManager = transactionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAutoCreate() {
|
||||||
|
return autoCreate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoCreate(Boolean autoCreate) {
|
||||||
|
this.autoCreate = autoCreate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStep() {
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStep(Integer step) {
|
||||||
|
if (step == 0)
|
||||||
|
step = 1;
|
||||||
|
this.step = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableConfig getTableConfig() {
|
||||||
|
return tableConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableConfig(TableConfig tableConfig) {
|
||||||
|
this.tableConfig = tableConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/main/java/com/cdhncy/seq/config/TableConfig.java
Normal file
74
src/main/java/com/cdhncy/seq/config/TableConfig.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package com.cdhncy.seq.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成器对应的数据库表和字段配置
|
||||||
|
*
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/30
|
||||||
|
*/
|
||||||
|
public class TableConfig {
|
||||||
|
/**
|
||||||
|
* 当前序号表名,闲置序号表会在该名称后增加后缀_unused,未锁定序号表会在该名称后增加unlock
|
||||||
|
*/
|
||||||
|
private String table = "sequences";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号英文名称,和序号类型组成唯一组件
|
||||||
|
*/
|
||||||
|
private String keyColumn = "key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号类型
|
||||||
|
*/
|
||||||
|
private String typeColumn = "type";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号值
|
||||||
|
*/
|
||||||
|
private String seqColumn = "seq";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未锁定序号使用时间
|
||||||
|
*/
|
||||||
|
private String createTimeColumn = "create_time";
|
||||||
|
|
||||||
|
public String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTable(String table) {
|
||||||
|
this.table = table.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyColumn() {
|
||||||
|
return keyColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyColumn(String keyColumn) {
|
||||||
|
this.keyColumn = keyColumn.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTypeColumn() {
|
||||||
|
return typeColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeColumn(String typeColumn) {
|
||||||
|
this.typeColumn = typeColumn.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSeqColumn() {
|
||||||
|
return seqColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeqColumn(String seqColumn) {
|
||||||
|
this.seqColumn = seqColumn.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreateTimeColumn() {
|
||||||
|
return createTimeColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTimeColumn(String createTimeColumn) {
|
||||||
|
this.createTimeColumn = createTimeColumn.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/main/java/com/cdhncy/seq/dao/SequencesDao.java
Normal file
26
src/main/java/com/cdhncy/seq/dao/SequencesDao.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cdhncy.seq.dao;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.po.Sequences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public interface SequencesDao {
|
||||||
|
/**
|
||||||
|
* 查找最后被使用的序号
|
||||||
|
*/
|
||||||
|
Sequences find(Sequences sequences);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存新生成的序号
|
||||||
|
*/
|
||||||
|
boolean save(Sequences sequences);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新被使用的序号
|
||||||
|
*/
|
||||||
|
boolean update(Sequences sequences);
|
||||||
|
|
||||||
|
void createTable();
|
||||||
|
}
|
||||||
44
src/main/java/com/cdhncy/seq/dao/SequencesUnlockDao.java
Normal file
44
src/main/java/com/cdhncy/seq/dao/SequencesUnlockDao.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package com.cdhncy.seq.dao;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.po.SequencesUnlock;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public interface SequencesUnlockDao {
|
||||||
|
/**
|
||||||
|
* 保存使用中的序号
|
||||||
|
*/
|
||||||
|
boolean save(SequencesUnlock sequencesUnlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除使用中的序号
|
||||||
|
*/
|
||||||
|
boolean delete(SequencesUnlock sequencesUnlock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出所有使用中的序号
|
||||||
|
*/
|
||||||
|
List<SequencesUnlock> listAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出指定时间段内使用中的序号
|
||||||
|
*/
|
||||||
|
List<SequencesUnlock> listByDate(Date begin, Date end);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除所有使用中的序号
|
||||||
|
*/
|
||||||
|
boolean deleteAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定时间段内使用中的序号
|
||||||
|
*/
|
||||||
|
boolean deleteByDate(Date begin, Date end);
|
||||||
|
|
||||||
|
void createTable();
|
||||||
|
}
|
||||||
34
src/main/java/com/cdhncy/seq/dao/SequencesUnusedDao.java
Normal file
34
src/main/java/com/cdhncy/seq/dao/SequencesUnusedDao.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package com.cdhncy.seq.dao;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.po.SequencesUnused;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public interface SequencesUnusedDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key,type查找seq最小的空闲序号
|
||||||
|
*/
|
||||||
|
SequencesUnused findMinSeq(SequencesUnused sequencesUnused);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key,type查找seq最大的空闲序号
|
||||||
|
*/
|
||||||
|
SequencesUnused findMaxSeq(SequencesUnused sequencesUnused);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key,type,seq删除空闲序号
|
||||||
|
*/
|
||||||
|
boolean delete(SequencesUnused sequencesUnused);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量保存空闲序号
|
||||||
|
*/
|
||||||
|
boolean saveBatch(List<SequencesUnused> sequencesUnusedList);
|
||||||
|
|
||||||
|
void createTable();
|
||||||
|
}
|
||||||
72
src/main/java/com/cdhncy/seq/dao/impl/SequencesDaoImpl.java
Normal file
72
src/main/java/com/cdhncy/seq/dao/impl/SequencesDaoImpl.java
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package com.cdhncy.seq.dao.impl;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.config.TableConfig;
|
||||||
|
import com.cdhncy.seq.dao.SequencesDao;
|
||||||
|
import com.cdhncy.seq.po.Sequences;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class SequencesDaoImpl implements SequencesDao {
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
private final TableConfig tableConfig;
|
||||||
|
|
||||||
|
public SequencesDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig) {
|
||||||
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
|
this.tableConfig = tableConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Sequences find(Sequences sequences) {
|
||||||
|
String sql = "select * from `%s` where `%s`=? and `%s`=?";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn());
|
||||||
|
try {
|
||||||
|
return this.jdbcTemplate.queryForObject(sql, (rs, rowNum) -> {
|
||||||
|
Sequences result = new Sequences();
|
||||||
|
result.setKey(rs.getString(tableConfig.getKeyColumn()));
|
||||||
|
result.setType(rs.getString(tableConfig.getTypeColumn()));
|
||||||
|
result.setSeq(rs.getLong(tableConfig.getSeqColumn()));
|
||||||
|
return result;
|
||||||
|
}, sequences.getKey(), sequences.getType());
|
||||||
|
} catch (EmptyResultDataAccessException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean save(Sequences sequences) {
|
||||||
|
String sql = "insert into `%s`(`%s`,`%s`,`%s`) values(?,?,?)";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
|
||||||
|
int result = this.jdbcTemplate.update(sql, sequences.getKey(), sequences.getType(), sequences.getSeq());
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean update(Sequences sequences) {
|
||||||
|
String sql = "update `%s` set `%s`=? where `%s`=? and `%s`=?";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getSeqColumn(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn());
|
||||||
|
int result = this.jdbcTemplate.update(sql, sequences.getSeq(), sequences.getKey(), sequences.getType());
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createTable() {
|
||||||
|
String sql = "CREATE TABLE IF NOT EXISTS `%s` ( " +
|
||||||
|
" `%s` VARCHAR ( 255 ) NOT NULL COMMENT '序号英文名称'," +
|
||||||
|
" `%s` VARCHAR ( 255 ) NOT NULL COMMENT '序号类型'," +
|
||||||
|
" `%s` BIGINT ( 2 ) NOT NULL COMMENT '已使用到的序号'," +
|
||||||
|
" PRIMARY KEY ( `%s`, `%s` ) " +
|
||||||
|
" ) COMMENT '当前序号表'";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(),
|
||||||
|
tableConfig.getKeyColumn(),
|
||||||
|
tableConfig.getTypeColumn(),
|
||||||
|
tableConfig.getSeqColumn(),
|
||||||
|
tableConfig.getKeyColumn(),
|
||||||
|
tableConfig.getTypeColumn());
|
||||||
|
this.jdbcTemplate.execute(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.cdhncy.seq.dao.impl;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.config.TableConfig;
|
||||||
|
import com.cdhncy.seq.dao.SequencesUnlockDao;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnlock;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class SequencesUnlockDaoImpl implements SequencesUnlockDao {
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
private final TableConfig tableConfig;
|
||||||
|
|
||||||
|
public SequencesUnlockDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig) {
|
||||||
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
|
this.tableConfig = tableConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean save(SequencesUnlock sequencesUnlock) {
|
||||||
|
String sql = "insert into `%s_unlock`(`%s`,`%s`,`%s`,`%s`) values(?,?,?,?)";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn(), tableConfig.getCreateTimeColumn());
|
||||||
|
int result = this.jdbcTemplate.update(sql, sequencesUnlock.getKey(), sequencesUnlock.getType(), sequencesUnlock.getSeq(), sequencesUnlock.getCreateTime());
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete(SequencesUnlock sequencesUnlock) {
|
||||||
|
String sql = "delete from `%s_unlock` where `%s`=? and `%s`=? and `%s`=?";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
|
||||||
|
int result = this.jdbcTemplate.update(sql, sequencesUnlock.getKey(), sequencesUnlock.getType(), sequencesUnlock.getSeq());
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SequencesUnlock> listAll() {
|
||||||
|
String sql = "select * from `%s_unlock`";
|
||||||
|
sql = String.format(sql, tableConfig.getTable());
|
||||||
|
return this.jdbcTemplate.query(sql, rowMapper());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SequencesUnlock> listByDate(Date begin, Date end) {
|
||||||
|
String sql = "select * from `%s_unlock` where `%s`>=? and `%s`<=?";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn());
|
||||||
|
return this.jdbcTemplate.query(sql, rowMapper(), begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteAll() {
|
||||||
|
String sql = "delete from `%s_unlock`";
|
||||||
|
sql = String.format(sql, tableConfig.getTable());
|
||||||
|
int result = this.jdbcTemplate.update(sql);
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteByDate(Date begin, Date end) {
|
||||||
|
String sql = "delete from `%s_unlock` where `%s`>=? and `%s`<=?";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn());
|
||||||
|
int result = this.jdbcTemplate.update(sql, begin, end);
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createTable() {
|
||||||
|
String sql = "CREATE TABLE IF NOT EXISTS `%s_unlock` ( " +
|
||||||
|
" `%s` VARCHAR ( 255 ) NOT NULL COMMENT '序号英文名称'," +
|
||||||
|
" `%s` VARCHAR ( 255 ) NOT NULL COMMENT '序号类型'," +
|
||||||
|
" `%s` BIGINT ( 2 ) NOT NULL COMMENT '尚未锁定的序号'," +
|
||||||
|
" `%s` DATETIME NOT NULL COMMENT '使用时间'," +
|
||||||
|
" PRIMARY KEY ( `%s`, `%s` ,`%s` ) " +
|
||||||
|
" ) COMMENT '未锁定序号表'";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(),
|
||||||
|
tableConfig.getKeyColumn(),
|
||||||
|
tableConfig.getTypeColumn(),
|
||||||
|
tableConfig.getSeqColumn(),
|
||||||
|
tableConfig.getCreateTimeColumn(),
|
||||||
|
tableConfig.getKeyColumn(),
|
||||||
|
tableConfig.getTypeColumn(),
|
||||||
|
tableConfig.getSeqColumn());
|
||||||
|
this.jdbcTemplate.execute(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RowMapper<SequencesUnlock> rowMapper() {
|
||||||
|
return (rs, rowNum) -> {
|
||||||
|
SequencesUnlock sequencesUnlock = new SequencesUnlock();
|
||||||
|
sequencesUnlock.setKey(rs.getString(tableConfig.getKeyColumn()));
|
||||||
|
sequencesUnlock.setType(rs.getString(tableConfig.getTypeColumn()));
|
||||||
|
sequencesUnlock.setSeq(rs.getLong(tableConfig.getSeqColumn()));
|
||||||
|
sequencesUnlock.setCreateTime(rs.getDate(tableConfig.getCreateTimeColumn()));
|
||||||
|
return sequencesUnlock;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package com.cdhncy.seq.dao.impl;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.config.TableConfig;
|
||||||
|
import com.cdhncy.seq.dao.SequencesUnusedDao;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnused;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class SequencesUnusedDaoImpl implements SequencesUnusedDao {
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
private final TableConfig tableConfig;
|
||||||
|
|
||||||
|
public SequencesUnusedDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig) {
|
||||||
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
|
this.tableConfig = tableConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SequencesUnused findMinSeq(SequencesUnused sequencesUnused) {
|
||||||
|
String sql = "select * from `%s_ununsed` where `%s`=? and `%s`=? order by `%s` asc limit 0,1";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
|
||||||
|
try {
|
||||||
|
return this.jdbcTemplate.queryForObject(sql, rowMapper(), sequencesUnused.getKey(), sequencesUnused.getType());
|
||||||
|
} catch (EmptyResultDataAccessException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SequencesUnused findMaxSeq(SequencesUnused sequencesUnused) {
|
||||||
|
try {
|
||||||
|
String sql = "select * from `%s_ununsed` where `%s`=? and `%s`=? order by `%s` desc limit 0,1";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
|
||||||
|
return this.jdbcTemplate.queryForObject(sql, rowMapper(), sequencesUnused.getKey(), sequencesUnused.getType());
|
||||||
|
} catch (EmptyResultDataAccessException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete(SequencesUnused sequencesUnused) {
|
||||||
|
String sql = "delete from `%s_ununsed` where `%s`=? and `%s`=? and `%s`=?";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
|
||||||
|
int result = this.jdbcTemplate.update(sql, sequencesUnused.getKey(), sequencesUnused.getType(), sequencesUnused.getSeq());
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveBatch(List<SequencesUnused> sequencesUnusedList) {
|
||||||
|
String sql = "insert into `%s_ununsed`(`%s`,`%s`,`%s`) values(?,?,?)";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
|
||||||
|
int[] result = this.jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
|
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||||
|
SequencesUnused sequencesUnused = sequencesUnusedList.get(i);
|
||||||
|
ps.setString(1, sequencesUnused.getKey());
|
||||||
|
ps.setString(2, sequencesUnused.getType());
|
||||||
|
ps.setLong(3, sequencesUnused.getSeq());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBatchSize() {
|
||||||
|
return sequencesUnusedList.size();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result.length != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createTable() {
|
||||||
|
String sql = "CREATE TABLE IF NOT EXISTS `%s_ununsed` ( " +
|
||||||
|
" `%s` VARCHAR ( 255 ) NOT NULL COMMENT '序号英文名称'," +
|
||||||
|
" `%s` VARCHAR ( 255 ) NOT NULL COMMENT '序号类型'," +
|
||||||
|
" `%s` BIGINT ( 2 ) NOT NULL COMMENT '闲置的的序号'," +
|
||||||
|
" PRIMARY KEY ( `%s`, `%s`, `%s` ) " +
|
||||||
|
" ) COMMENT '闲置序号表'";
|
||||||
|
sql = String.format(sql, tableConfig.getTable(),
|
||||||
|
tableConfig.getKeyColumn(),
|
||||||
|
tableConfig.getTypeColumn(),
|
||||||
|
tableConfig.getSeqColumn(),
|
||||||
|
tableConfig.getKeyColumn(),
|
||||||
|
tableConfig.getTypeColumn(),
|
||||||
|
tableConfig.getSeqColumn());
|
||||||
|
this.jdbcTemplate.execute(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RowMapper<SequencesUnused> rowMapper() {
|
||||||
|
return (rs, rowNum) -> {
|
||||||
|
SequencesUnused result = new SequencesUnused();
|
||||||
|
result.setKey(rs.getString(tableConfig.getKeyColumn()));
|
||||||
|
result.setType(rs.getString(tableConfig.getTypeColumn()));
|
||||||
|
result.setSeq(rs.getLong(tableConfig.getSeqColumn()));
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
114
src/main/java/com/cdhncy/seq/generator/Generator.java
Normal file
114
src/main/java/com/cdhncy/seq/generator/Generator.java
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package com.cdhncy.seq.generator;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.po.Sequences;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnlock;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnused;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface Generator {
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的年
|
||||||
|
*/
|
||||||
|
String YEAR = "#year#";
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的月
|
||||||
|
*/
|
||||||
|
String MONTH = "#month#";
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的日
|
||||||
|
*/
|
||||||
|
String DAY = "#day#";
|
||||||
|
/**
|
||||||
|
* 序号格式字符中的格式化后的序号
|
||||||
|
*/
|
||||||
|
String SEQ = "#seq#";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据传入的key和type生成可用的序号对象。
|
||||||
|
* <p/>
|
||||||
|
* 如果根据key和type在{@link Sequences}中找不到记录,说明该组合的序号对象还未初次生成,返回的是seq为step的序号对象,该对象数据会写入到{@link SequencesUnlock}中。
|
||||||
|
* <p/>
|
||||||
|
* 如果根据key和type在{@link Sequences}中找到了记录,且在{@link SequencesUnused}也找到了记录,说明该组合生成的序号有部分未使用,返回的是{@link SequencesUnused}中找到的seq最小的序号对象。同时会将{@link SequencesUnused}中找到的seq最小的记录删除,然后写入到{@link SequencesUnlock}中。
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @param key 数据字典中的编码
|
||||||
|
* @param type 序号类型
|
||||||
|
* @return 可用的序号对象
|
||||||
|
*/
|
||||||
|
Sequences generate(String key, String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回根据{@link #generate(String, String)}得到的序号对象,补零后的序号字符串
|
||||||
|
* <p/>
|
||||||
|
* 如生成的为3,而minLength为5,则返回的是00003
|
||||||
|
*
|
||||||
|
* @param key 数据字典中的编码
|
||||||
|
* @param type 序号类型
|
||||||
|
* @param minLength 序号数字最小长度
|
||||||
|
* @return 补零后的字符串
|
||||||
|
*/
|
||||||
|
String generate(String key, String type, Integer minLength);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将生成的序号对象格式化为指定格式
|
||||||
|
* <p/>
|
||||||
|
* pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量
|
||||||
|
* <p/>
|
||||||
|
* seq为1,minLength为4,pattern为#year##month##day#6#seq#,则会格式化为2022013060001。此序号含义如下:
|
||||||
|
* <p/>
|
||||||
|
* 序号格式:[年][月][日][固定6开头][序号1,最小位数为4位,不足4位则补零]
|
||||||
|
*
|
||||||
|
* @param seq 需要格式化的序号
|
||||||
|
* @param minLength 序号最小长度,不足的会补零
|
||||||
|
* @param pattern 格式
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
String format(Long seq, Integer minLength, String pattern);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将生成的序号对象格式化为指定格式
|
||||||
|
* <p/>
|
||||||
|
* pattern支持:{@link #YEAR}(当前年份)、{@link #MONTH}(当前月份)、{@link #DAY}(当前日期)、{@link #SEQ}(生成的字符串序号)四个变量
|
||||||
|
* <p/>
|
||||||
|
* seq为1,start为6,minLength为4,pattern为#year##month##day##seq#,则会格式化为2022013060001。此序号含义如下:
|
||||||
|
* <p/>
|
||||||
|
* 序号格式:[年][月][日][固定6开头][序号1,最小位数为4位,不足4位则补零]
|
||||||
|
*
|
||||||
|
* @param seq 需要格式化的序号
|
||||||
|
* @param start 序号格式化后以什么字符串开头
|
||||||
|
* @param minLength 序号最小长度,不足的会补零
|
||||||
|
* @param pattern 格式
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
String format(Long seq, String start, Integer minLength, String pattern);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 锁定指定序号,在序号生成后,调用该序号的逻辑完成后需要执行此方法
|
||||||
|
* <p/>
|
||||||
|
* 如办理案件时,先调用{@link #generate(String, String)}或者{@link #generate(String, String, Integer)}生成了序号,之后对案件进行了入库,如果入库完毕,则将该序号锁定,说明这个序号已被使用
|
||||||
|
* <p/>
|
||||||
|
* 注意,此处的锁定非数据库中锁定,而是{@link SequencesUnused}和{@link SequencesUnlock}中均不存在key、type、seq相同的记录视为锁定。因此此处实际是把这两个表中的记录均删除了
|
||||||
|
*
|
||||||
|
* @param sequences 需要锁定的序号
|
||||||
|
* @return 锁定结果
|
||||||
|
*/
|
||||||
|
boolean lock(Sequences sequences);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放所有未使用的序号
|
||||||
|
* <p/>
|
||||||
|
* {@link SequencesUnlock}中未通过{@link #lock(Sequences)}方法锁定的序号会一直存在,调用此方法会将里面的所有序号都移动到{@link SequencesUnused}中,下次生成序号时优先从{@link SequencesUnused}获取。
|
||||||
|
*/
|
||||||
|
void release();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放指定时间段内未使用的序号
|
||||||
|
* <p/>
|
||||||
|
* {@link SequencesUnlock}中未通过{@link #lock(Sequences)}方法锁定的序号会一直存在,调用此方法会将里面的所有序号都移动到{@link SequencesUnused}中,下次生成序号时优先从{@link SequencesUnused}获取。
|
||||||
|
*
|
||||||
|
* @param begin 开始时间
|
||||||
|
* @param end 结束时间
|
||||||
|
*/
|
||||||
|
void release(Date begin, Date end);
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
package com.cdhncy.seq.generator.impl;
|
||||||
|
|
||||||
|
import com.cdhncy.seq.config.GeneratorConfig;
|
||||||
|
import com.cdhncy.seq.dao.SequencesDao;
|
||||||
|
import com.cdhncy.seq.dao.SequencesUnusedDao;
|
||||||
|
import com.cdhncy.seq.dao.SequencesUnlockDao;
|
||||||
|
import com.cdhncy.seq.dao.impl.SequencesDaoImpl;
|
||||||
|
import com.cdhncy.seq.dao.impl.SequencesUnusedDaoImpl;
|
||||||
|
import com.cdhncy.seq.dao.impl.SequencesUnlockDaoImpl;
|
||||||
|
import com.cdhncy.seq.po.Sequences;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnused;
|
||||||
|
import com.cdhncy.seq.po.SequencesUnlock;
|
||||||
|
import com.cdhncy.seq.generator.Generator;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||||
|
import org.springframework.jdbc.support.JdbcTransactionManager;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class SequencesGenerator implements Generator {
|
||||||
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
private final SequencesDao sequencesDao;
|
||||||
|
private final SequencesUnusedDao sequencesUnusedDao;
|
||||||
|
private final SequencesUnlockDao sequencesUnlockDao;
|
||||||
|
private final Integer step;
|
||||||
|
|
||||||
|
public SequencesGenerator(GeneratorConfig generatorConfig) {
|
||||||
|
//数据库操作模板
|
||||||
|
JdbcTemplate jdbcTemplate = generatorConfig.getJdbcTemplate();
|
||||||
|
|
||||||
|
if (jdbcTemplate == null) {
|
||||||
|
//数据源
|
||||||
|
DataSource dataSource = generatorConfig.getDataSource();
|
||||||
|
if (dataSource == null)
|
||||||
|
//若数据库操作模板为空,也没有配置数据源,则抛出异常
|
||||||
|
throw new NullPointerException("数据源不能为空");
|
||||||
|
//否则以数据源创建数据库操作模板
|
||||||
|
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generatorConfig.getTransactionTemplate() == null) {
|
||||||
|
//若没有配置事务操作模板,则从配置中取事务管理器
|
||||||
|
DataSourceTransactionManager transactionManager = generatorConfig.getTransactionManager();
|
||||||
|
if (transactionManager == null) {
|
||||||
|
//若未配置事务管理器,则通过数据源新建
|
||||||
|
DataSource dataSource = jdbcTemplate.getDataSource();
|
||||||
|
if (dataSource == null)
|
||||||
|
throw new NullPointerException("数据源不能为空");
|
||||||
|
transactionManager = new JdbcTransactionManager(dataSource);
|
||||||
|
}
|
||||||
|
//通过事务管理器创建事务操作模板
|
||||||
|
transactionTemplate = new TransactionTemplate(transactionManager);
|
||||||
|
} else {
|
||||||
|
//获取事务操作模板
|
||||||
|
transactionTemplate = generatorConfig.getTransactionTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sequencesDao = new SequencesDaoImpl(jdbcTemplate, generatorConfig.getTableConfig());
|
||||||
|
this.sequencesUnusedDao = new SequencesUnusedDaoImpl(jdbcTemplate, generatorConfig.getTableConfig());
|
||||||
|
this.sequencesUnlockDao = new SequencesUnlockDaoImpl(jdbcTemplate, generatorConfig.getTableConfig());
|
||||||
|
this.step = generatorConfig.getStep();
|
||||||
|
|
||||||
|
autoCreateTable(generatorConfig.getAutoCreate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动创建需要的表
|
||||||
|
*/
|
||||||
|
private void autoCreateTable(Boolean autoCreate) {
|
||||||
|
if (!autoCreate)
|
||||||
|
return;
|
||||||
|
this.sequencesDao.createTable();
|
||||||
|
this.sequencesUnusedDao.createTable();
|
||||||
|
this.sequencesUnlockDao.createTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Sequences generate(String key, String type) {
|
||||||
|
return transactionTemplate.execute(status -> {
|
||||||
|
try {
|
||||||
|
//根据传入的key和type新生成查询条件对象
|
||||||
|
Sequences condition = new Sequences(key, type);
|
||||||
|
|
||||||
|
//找到正在使用的最大序号
|
||||||
|
Sequences sequences = sequencesDao.find(condition);
|
||||||
|
if (sequences == null) {
|
||||||
|
//不存在,说明还没生成,将新生成的入库,此时序号为默认的0
|
||||||
|
sequences = condition;
|
||||||
|
sequencesDao.save(sequences);
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据传入的key和type查找空闲编号最小的一个
|
||||||
|
SequencesUnused conditionIdle = new SequencesUnused(condition);
|
||||||
|
SequencesUnused sequencesUnused = sequencesUnusedDao.findMinSeq(conditionIdle);
|
||||||
|
|
||||||
|
if (sequencesUnused == null) {
|
||||||
|
//空闲编号不存在,说明是未生成过,序号需要增加后直接使用,同时将新生成的写入到使用中表
|
||||||
|
sequences.increase(step);
|
||||||
|
SequencesUnlock sequencesUnlock = new SequencesUnlock(sequences);
|
||||||
|
sequencesUnlock.setCreateTime(new Date());
|
||||||
|
|
||||||
|
sequencesDao.update(sequences);
|
||||||
|
sequencesUnlockDao.save(sequencesUnlock);
|
||||||
|
} else {
|
||||||
|
//空闲编号存在,说明已经生成过,序号不需要增加,直接使用。同时将该空闲编号移动到使用中表
|
||||||
|
sequences = new Sequences(sequencesUnused);
|
||||||
|
SequencesUnlock sequencesUnlock = new SequencesUnlock(sequencesUnused);
|
||||||
|
sequencesUnlock.setCreateTime(new Date());
|
||||||
|
|
||||||
|
sequencesUnlockDao.save(sequencesUnlock);
|
||||||
|
sequencesUnusedDao.delete(sequencesUnused);
|
||||||
|
}
|
||||||
|
return sequences;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
status.setRollbackOnly();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String generate(String key, String type, Integer minLength) {
|
||||||
|
Sequences sequences = this.generate(key, type);
|
||||||
|
if (sequences == null)
|
||||||
|
return null;
|
||||||
|
return sequences.format(minLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(Long seq, Integer minLength, String pattern) {
|
||||||
|
return format(seq, null, minLength, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(Long seq, String start, Integer minLength, String pattern) {
|
||||||
|
if (start == null)
|
||||||
|
start = "";
|
||||||
|
String seqString = start + new Sequences(seq).format(minLength);
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
pattern = pattern.replaceAll(Generator.YEAR, String.valueOf(calendar.get(Calendar.YEAR)));
|
||||||
|
pattern = pattern.replaceAll(Generator.MONTH, String.format("%02d", calendar.get(Calendar.MONTH) + 1));
|
||||||
|
pattern = pattern.replaceAll(Generator.DAY, String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)));
|
||||||
|
pattern = pattern.replaceAll(Generator.SEQ, seqString);
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized boolean lock(Sequences sequences) {
|
||||||
|
SequencesUnlock condition = new SequencesUnlock(sequences);
|
||||||
|
//将使用中表的对应数据删除,空闲表中数据在生成时会删除,因此这里不需要处理该表
|
||||||
|
return sequencesUnlockDao.delete(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
//列出所有使用中表存在的序号
|
||||||
|
List<SequencesUnlock> sequencesUnlockList = sequencesUnlockDao.listAll();
|
||||||
|
|
||||||
|
List<SequencesUnused> sequencesUnusedList = new ArrayList<>();
|
||||||
|
for (SequencesUnlock sequencesUnlock : sequencesUnlockList) {
|
||||||
|
sequencesUnusedList.add(new SequencesUnused(sequencesUnlock));
|
||||||
|
}
|
||||||
|
|
||||||
|
//将使用中表的序号放到空闲表中
|
||||||
|
sequencesUnusedDao.saveBatch(sequencesUnusedList);
|
||||||
|
//删除所有使用中表的数据
|
||||||
|
sequencesUnlockDao.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release(Date begin, Date end) {
|
||||||
|
//列出指定时间段内使用中表存在的序号
|
||||||
|
List<SequencesUnlock> sequencesUnlockList = sequencesUnlockDao.listByDate(begin, end);
|
||||||
|
|
||||||
|
List<SequencesUnused> sequencesUnusedList = new ArrayList<>();
|
||||||
|
for (SequencesUnlock sequencesUnlock : sequencesUnlockList) {
|
||||||
|
sequencesUnusedList.add(new SequencesUnused(sequencesUnlock));
|
||||||
|
}
|
||||||
|
|
||||||
|
//将指定时间段内使用中表的序号放到空闲表中
|
||||||
|
sequencesUnusedDao.saveBatch(sequencesUnusedList);
|
||||||
|
//删除指定时间段内使用中表的数据
|
||||||
|
sequencesUnlockDao.deleteByDate(begin, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
88
src/main/java/com/cdhncy/seq/po/Sequences.java
Normal file
88
src/main/java/com/cdhncy/seq/po/Sequences.java
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package com.cdhncy.seq.po;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前序号
|
||||||
|
*
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class Sequences {
|
||||||
|
/**
|
||||||
|
* 需要生成序号的key,和type组成唯一主键
|
||||||
|
*/
|
||||||
|
protected String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要生成序号的类型,和key组成唯一主键
|
||||||
|
*/
|
||||||
|
protected String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认序号
|
||||||
|
*/
|
||||||
|
protected Long seq = 0L;
|
||||||
|
|
||||||
|
public Sequences() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sequences(Long seq) {
|
||||||
|
this.seq = seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sequences(String key, String type) {
|
||||||
|
this.key = key;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sequences(SequencesUnused sequencesUnused) {
|
||||||
|
this.key = sequencesUnused.getKey();
|
||||||
|
this.type = sequencesUnused.getType();
|
||||||
|
this.seq = sequencesUnused.getSeq();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSeq() {
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSeq(Long seq) {
|
||||||
|
this.seq = seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将序号增加指定步长
|
||||||
|
*
|
||||||
|
* @param step 步长
|
||||||
|
*/
|
||||||
|
public void increase(Integer step) {
|
||||||
|
this.seq += step;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序号补零
|
||||||
|
*
|
||||||
|
* @param minLength 最小长度,低于此长度,会填充零
|
||||||
|
* @return 补零后的序号
|
||||||
|
*/
|
||||||
|
public String format(Integer minLength) {
|
||||||
|
if (minLength != null)
|
||||||
|
return String.format("%0" + minLength + "d", this.seq);
|
||||||
|
return String.valueOf(this.seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/main/java/com/cdhncy/seq/po/SequencesUnlock.java
Normal file
37
src/main/java/com/cdhncy/seq/po/SequencesUnlock.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package com.cdhncy.seq.po;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未锁定序号
|
||||||
|
*
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class SequencesUnlock extends Sequences {
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
public SequencesUnlock() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SequencesUnlock(Sequences sequences) {
|
||||||
|
this.key = sequences.getKey();
|
||||||
|
this.type = sequences.getType();
|
||||||
|
this.seq = sequences.getSeq();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SequencesUnlock(SequencesUnused sequencesUnused) {
|
||||||
|
this.key = sequencesUnused.getKey();
|
||||||
|
this.type = sequencesUnused.getType();
|
||||||
|
this.seq = sequencesUnused.getSeq();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Date createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/main/java/com/cdhncy/seq/po/SequencesUnused.java
Normal file
19
src/main/java/com/cdhncy/seq/po/SequencesUnused.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package com.cdhncy.seq.po;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 闲置序号
|
||||||
|
*
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class SequencesUnused extends Sequences {
|
||||||
|
public SequencesUnused() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SequencesUnused(Sequences sequences) {
|
||||||
|
this.key = sequences.getKey();
|
||||||
|
this.type = sequences.getType();
|
||||||
|
this.seq = sequences.getSeq();
|
||||||
|
}
|
||||||
|
}
|
||||||
76
src/test/java/SeqTest.java
Normal file
76
src/test/java/SeqTest.java
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import com.cdhncy.seq.config.GeneratorConfig;
|
||||||
|
import com.cdhncy.seq.config.TableConfig;
|
||||||
|
import com.cdhncy.seq.po.Sequences;
|
||||||
|
import com.cdhncy.seq.generator.Generator;
|
||||||
|
import com.cdhncy.seq.generator.impl.SequencesGenerator;
|
||||||
|
import com.mysql.cj.jdbc.MysqlDataSource;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanghuanglin
|
||||||
|
* @since 2022/1/28
|
||||||
|
*/
|
||||||
|
public class SeqTest {
|
||||||
|
private static final MysqlDataSource dataSource = new MysqlDataSource();
|
||||||
|
private static final Generator generator;
|
||||||
|
|
||||||
|
static {
|
||||||
|
dataSource.setURL("jdbc:mysql://127.0.0.1:3306/sequence");
|
||||||
|
dataSource.setUser("root");
|
||||||
|
dataSource.setPassword("root");
|
||||||
|
|
||||||
|
GeneratorConfig generatorConfig = new GeneratorConfig(dataSource);
|
||||||
|
TableConfig tableConfig = new TableConfig();
|
||||||
|
// tableConfig.setTable("sequences");
|
||||||
|
// tableConfig.setKeyColumn("SEQUENCE_KEY");
|
||||||
|
// tableConfig.setTypeColumn("SEQUENCE_TYPE");
|
||||||
|
// tableConfig.setSeqColumn("SEQUENCE_NEXT_ID");
|
||||||
|
generatorConfig.setTableConfig(tableConfig);
|
||||||
|
|
||||||
|
generator = new SequencesGenerator(generatorConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateTest() {
|
||||||
|
//释放未锁定序列号
|
||||||
|
generator.release();
|
||||||
|
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100));
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
int finalI = i;
|
||||||
|
threadPoolExecutor.execute(() -> {
|
||||||
|
Sequences sequences = generator.generate("SNT", "MISSION");
|
||||||
|
String formattedSeq = generator.format(sequences.getSeq(), 5, "处〔#year#〕10801#seq#");
|
||||||
|
// if (finalI % 2 == 0)
|
||||||
|
// System.out.println(3 / 0);
|
||||||
|
generator.lock(sequences);
|
||||||
|
set.add(formattedSeq);
|
||||||
|
System.out.println(formattedSeq);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
threadPoolExecutor.shutdown();
|
||||||
|
while (true) {
|
||||||
|
if (threadPoolExecutor.isTerminated())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
System.out.println(set.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void releaseTest() {
|
||||||
|
generator.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatTest() {
|
||||||
|
String s = "select * from sequences where `%s`=? and `%s`=?";
|
||||||
|
System.out.println(String.format(s, "key", "value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user