refactor(sequence): 重构sequence 使用anyline 实现数据库创表抽象

This commit is contained in:
冷冷 committed 2024-08-22 09:40:41 +08:00
1 parent f914c2385a
commit 83935f26ce
23 files changed
+388 -962

No files matched your search

+43 -31
View File
@@ -1,37 +1,49 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common</artifactId>
<version>5.5.0</version>
</parent>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common</artifactId>
<version>5.5.0</version>
</parent>
<artifactId>pigx-common-sequence</artifactId>
<packaging>jar</packaging>
<artifactId>pigx-common-sequence</artifactId>
<packaging>jar</packaging>
<description>pigx 分布式发号器</description>
<description>pigx 分布式发号器</description>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-core</artifactId>
</dependency>
<!--mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-core</artifactId>
</dependency>
<!-- redis 实现-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--anyline-->
<dependency>
<groupId>org.anyline</groupId>
<artifactId>anyline-environment-spring-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.anyline</groupId>
<artifactId>anyline-data-jdbc-mysql</artifactId>
</dependency>
<dependency>
<groupId>org.anyline</groupId>
<artifactId>anyline-data-jdbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.anyline</groupId>
<artifactId>anyline-data-jdbc-oracle</artifactId>
</dependency>
<dependency>
<groupId>org.anyline</groupId>
<artifactId>anyline-data-jdbc-dm</artifactId>
</dependency>
</dependencies>
</project>
@@ -17,34 +17,58 @@
package com.pig4cloud.pigx.common.sequence;
import com.pig4cloud.pigx.common.sequence.builder.SnowflakeSeqBuilder;
import com.pig4cloud.pigx.common.sequence.properties.SequenceSnowflakeProperties;
import com.pig4cloud.pigx.common.sequence.sequence.Sequence;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import com.pig4cloud.pigx.common.sequence.properties.BaseSequenceProperties;
import com.pig4cloud.pigx.common.sequence.range.impl.db.SequenceTable;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.anyline.metadata.Column;
import org.anyline.metadata.Index;
import org.anyline.metadata.Table;
import org.anyline.proxy.ServiceProxy;
import org.anyline.service.AnylineService;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import java.util.LinkedHashMap;
import java.util.Objects;
/**
* @author lengleng
* @date 2019-05-26
*/
@Slf4j
@Configuration
@ComponentScan("com.pig4cloud.pigx.common.sequence")
@ConditionalOnMissingBean(Sequence.class)
@RequiredArgsConstructor
@EnableConfigurationProperties(BaseSequenceProperties.class)
public class SequenceAutoConfiguration {
/**
* snowflak 算法作为发号器实现
* @param properties
* @return
*/
@Bean
@ConditionalOnBean(SequenceSnowflakeProperties.class)
public Sequence snowflakeSequence(SequenceSnowflakeProperties properties) {
return SnowflakeSeqBuilder.create().datacenterId(properties.getDatacenterId())
.workerId(properties.getWorkerId()).build();
}
private final BaseSequenceProperties sequenceDbProperties;
}
/**
* 启动后自动创建表
*/
@EventListener({WebServerInitializedEvent.class})
public void onApplicationReady() throws Exception {
// 判断是否需要创建表
AnylineService service = ServiceProxy.service();
Table tableMetadata = service.metadata().table(sequenceDbProperties.getDb().getTableName(), false);
if (Objects.isNull(tableMetadata)) {
Table table = Table.from(SequenceTable.class);
table.setName(sequenceDbProperties.getDb().getTableName());
table.setComment("序列号区间管理表");
table.setPrimaryKey(SequenceTable.Fields.id);
LinkedHashMap<String, Index> indexLinkedHashMap = new LinkedHashMap<>();
Index nameUnique = new Index(SequenceTable.Fields.name);
nameUnique.setUnique(true);
nameUnique.addColumn(new Column(SequenceTable.Fields.name));
indexLinkedHashMap.put(SequenceTable.Fields.name, nameUnique);
table.setIndexes(indexLinkedHashMap);
service.ddl().create(table);
log.debug("发号器自动创建表成功:{} ", table);
}
}
}
@@ -53,7 +53,6 @@ public class DbSeqBuilder implements SeqBuilder {
public Sequence build() {
// 利用DB获取区间管理器
DbSeqRangeMgr dbSeqRangeMgr = new DbSeqRangeMgr();
dbSeqRangeMgr.setDataSource(this.dataSource);
dbSeqRangeMgr.setTableName(this.tableName);
dbSeqRangeMgr.setRetryTimes(this.retryTimes);
dbSeqRangeMgr.setStep(this.step);
@@ -1,9 +1,11 @@
package com.pig4cloud.pigx.common.sequence.builder;
import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
import com.pig4cloud.pigx.common.sequence.range.BizName;
import com.pig4cloud.pigx.common.sequence.range.impl.redis.RedisSeqRangeMgr;
import com.pig4cloud.pigx.common.sequence.sequence.Sequence;
import com.pig4cloud.pigx.common.sequence.sequence.impl.DefaultRangeSequence;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* 基于redis取步长,序列号生成器构建者
@@ -12,25 +14,11 @@ import com.pig4cloud.pigx.common.sequence.sequence.impl.DefaultRangeSequence;
*/
public class RedisSeqBuilder implements SeqBuilder {
/**
* 连接redis的IP[必选]
*/
private String ip;
/**
* 连接redis的port[必选]
*/
private int port;
/**
* 业务名称[必选]
*/
private BizName bizName;
/**
* 认证权限,看redis是否配置了需要密码auth[可选]
*/
private String auth;
/**
* 获取range步长[可选,默认:1000]
@@ -42,6 +30,7 @@ public class RedisSeqBuilder implements SeqBuilder {
*/
private long stepStart = 0;
public static RedisSeqBuilder create() {
RedisSeqBuilder builder = new RedisSeqBuilder();
return builder;
@@ -51,11 +40,9 @@ public class RedisSeqBuilder implements SeqBuilder {
public Sequence build() {
// 利用Redis获取区间管理器
RedisSeqRangeMgr redisSeqRangeMgr = new RedisSeqRangeMgr();
redisSeqRangeMgr.setIp(this.ip);
redisSeqRangeMgr.setPort(this.port);
redisSeqRangeMgr.setAuth(this.auth);
redisSeqRangeMgr.setStep(this.step);
redisSeqRangeMgr.setStringRedisTemplate(null);
redisSeqRangeMgr.setStepStart(stepStart);
redisSeqRangeMgr.setStringRedisTemplate(SpringContextHolder.getBean(StringRedisTemplate.class));
redisSeqRangeMgr.init();
// 构建序列号生成器
DefaultRangeSequence sequence = new DefaultRangeSequence();
@@ -64,20 +51,6 @@ public class RedisSeqBuilder implements SeqBuilder {
return sequence;
}
public RedisSeqBuilder ip(String ip) {
this.ip = ip;
return this;
}
public RedisSeqBuilder port(int port) {
this.port = port;
return this;
}
public RedisSeqBuilder auth(String auth) {
this.auth = auth;
return this;
}
public RedisSeqBuilder step(int step) {
this.step = step;
@@ -1,6 +1,8 @@
package com.pig4cloud.pigx.common.sequence.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
/**
* @author lengleng
@@ -9,21 +11,32 @@ import lombok.Data;
* 发号器通用属性
*/
@Data
class BaseSequenceProperties {
@ConfigurationProperties(prefix = "pigx.xsequence")
public class BaseSequenceProperties {
/**
* 获取range步长[可选,默认:1000]
*/
private int step = 1000;
/**
* 获取range步长[可选,默认:1000]
*/
private int step = 10;
/**
* 序列号分配起始值[可选:默认:0]
*/
private long stepStart = 0;
/**
* 序列号分配起始值[可选:默认:0]
*/
private long stepStart = 0;
/**
* 业务名称
*/
private String bizName = "pigx";
/**
* 业务名称
*/
private String bizName = "pigx";
@NestedConfigurationProperty
private SequenceSnowflakeProperties snowflake = new SequenceSnowflakeProperties();
@NestedConfigurationProperty
private SequenceRedisProperties redis = new SequenceRedisProperties();
@NestedConfigurationProperty
private SequenceDbProperties db = new SequenceDbProperties();
}
@@ -5,10 +5,7 @@ package com.pig4cloud.pigx.common.sequence.properties;
* @date 2019-05-26
*/
import com.baomidou.mybatisplus.annotation.DbType;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author lengleng
@@ -17,23 +14,16 @@ import org.springframework.stereotype.Component;
* 发号器DB配置属性
*/
@Data
@Component
@ConfigurationProperties(prefix = "pigx.xsequence.db")
public class SequenceDbProperties extends BaseSequenceProperties {
public class SequenceDbProperties {
/**
* 默认数据库类型
*/
private DbType dbType = DbType.MYSQL;
/**
* 表名称
*/
private String tableName = "pigx_sequence";
/**
* 表名称
*/
private String tableName = "pigx_sequence";
/**
* 重试次数
*/
private int retryTimes = 1;
/**
* 重试次数
*/
private int retryTimes = 1;
}
@@ -6,8 +6,6 @@ package com.pig4cloud.pigx.common.sequence.properties;
*/
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author lengleng
@@ -16,8 +14,6 @@ import org.springframework.stereotype.Component;
* 发号器Redis配置属性
*/
@Data
@Component
@ConfigurationProperties(prefix = "pigx.xsequence.redis")
public class SequenceRedisProperties extends BaseSequenceProperties {
public class SequenceRedisProperties {
}
}
@@ -1,8 +1,6 @@
package com.pig4cloud.pigx.common.sequence.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author lengleng
@@ -11,18 +9,16 @@ import org.springframework.stereotype.Component;
* Snowflake 发号器属性
*/
@Data
@Component
@ConfigurationProperties(prefix = "pigx.xsequence.snowflake")
public class SequenceSnowflakeProperties extends BaseSequenceProperties {
public class SequenceSnowflakeProperties {
/**
* 数据中心ID,值的范围在[0,31]之间,一般可以设置机房的IDC[必选]
*/
private long datacenterId;
/**
* 数据中心ID,值的范围在[0,31]之间,一般可以设置机房的IDC[必选]
*/
private long datacenterId;
/**
* 工作机器ID,值的范围在[0,31]之间,一般可以设置机器编号[必选]
*/
private long workerId;
/**
* 工作机器ID,值的范围在[0,31]之间,一般可以设置机器编号[必选]
*/
private long workerId;
}
@@ -9,17 +9,20 @@ import com.pig4cloud.pigx.common.sequence.exception.SeqException;
*/
public interface SeqRangeMgr {
/**
* 获取指定区间名的下一个区间
* @param name 区间名
* @return 返回区间
* @throws SeqException 异常
*/
SeqRange nextRange(String name) throws SeqException;
/**
* 获取指定区间名的下一个区间
*
* @param name 区间名
* @return 返回区间
* @throws SeqException 异常
*/
SeqRange nextRange(String name) throws SeqException;
/**
* 初始化
*/
default void init() {
}
/**
* 初始化
*/
void init();
}
@@ -1,13 +1,15 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
import cn.hutool.core.util.RandomUtil;
import com.pig4cloud.pigx.common.sequence.exception.SeqException;
import com.pig4cloud.pigx.common.sequence.range.impl.db.provider.SqlProviderFactory;
import org.anyline.data.param.ConfigStore;
import org.anyline.data.param.init.DefaultConfigStore;
import org.anyline.entity.DataRow;
import org.anyline.proxy.ServiceProxy;
import org.anyline.service.AnylineService;
import javax.sql.DataSource;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 操作DB帮助类
@@ -15,198 +17,67 @@ import java.sql.*;
* @author xuan on 2018/4/29.
*/
abstract class BaseDbHelper {
private static final long DELTA = 100000000L;
private static final SqlProviderFactory SQL_PROVIDER_FACTORY = SpringContextHolder
.getBean(SqlProviderFactory.class);
private static final long DELTA = 100000000L;
/**
* 更新区间,乐观策略
*
* @param tableName 表名
* @param newValue 更新新数据
* @param oldValue 更新旧数据
* @param name 区间名称
* @return 成功/失败
*/
static boolean updateRange(String tableName, Long newValue, Long oldValue, String name) {
AnylineService service = ServiceProxy.service();
SequenceTable sequenceTable = new SequenceTable();
sequenceTable.setValue(newValue);
sequenceTable.setGmtModified(LocalDateTime.now());
ConfigStore configs = new DefaultConfigStore();
configs.and("value", oldValue);
return service.update(tableName, sequenceTable, configs) > 0;
}
private final static DefaultIdentifierGenerator identifierGenerator = new DefaultIdentifierGenerator();
/**
* 查询区间,如果区间不存在,会新增一个区间,并返回null,由上层重新执行
*
* @param tableName 来源
* @param name 区间名称
* @param stepStart 初始位置
* @return 区间值
*/
static Long selectRange(String tableName, String name, long stepStart) {
AnylineService service = ServiceProxy.service();
DataRow dataRow = service.query(tableName, SequenceTable.Fields.name + ":" + name);
/**
* 创建表
* @param dataSource DB来源
* @param tableName 表名
*/
static void createTable(DataSource dataSource, String tableName) {
if (Objects.isNull(dataRow)) {
// 没有此类型数据,需要初始化
SequenceTable sequenceTable = new SequenceTable();
sequenceTable.setId(RandomUtil.getSecureRandom().nextLong());
sequenceTable.setName(name);
sequenceTable.setValue(stepStart);
sequenceTable.setGmtCreate(LocalDateTime.now());
sequenceTable.setGmtModified(LocalDateTime.now());
service.insert(tableName, sequenceTable);
return stepStart;
}
long oldValue = dataRow.getLong(SequenceTable.Fields.value);
Connection conn = null;
Statement stmt = null;
if (oldValue < 0) {
String msg = "Sequence value cannot be less than zero, value = " + oldValue
+ ", please check table sequence" + tableName;
throw new SeqException(msg);
}
try {
conn = dataSource.getConnection();
stmt = conn.createStatement();
stmt.executeUpdate(SQL_PROVIDER_FACTORY.getCreateTableSql().replace("#tableName", tableName));
}
catch (SQLException e) {
throw new SeqException(e);
}
finally {
closeQuietly(stmt);
closeQuietly(conn);
}
}
if (oldValue > Long.MAX_VALUE - DELTA) {
String msg = "Sequence value overflow, value = " + oldValue + ", please check table sequence"
+ tableName;
throw new SeqException(msg);
}
/**
* 插入数据区间
* @param dataSource DB来源
* @param tableName 表名
* @param name 区间名称
* @param stepStart 初始位置
*/
private static void insertRange(DataSource dataSource, String tableName, String name, long stepStart) {
return oldValue;
}
Connection conn = null;
PreparedStatement stmt = null;
try {
conn = dataSource.getConnection();
stmt = conn.prepareStatement(SQL_PROVIDER_FACTORY.getInsertRangeSql().replace("#tableName", tableName));
stmt.setLong(1, identifierGenerator.nextId(null));
stmt.setString(2, name);
stmt.setLong(3, stepStart);
stmt.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
stmt.setTimestamp(5, new Timestamp(System.currentTimeMillis()));
stmt.executeUpdate();
}
catch (SQLException e) {
throw new SeqException(e);
}
finally {
closeQuietly(stmt);
closeQuietly(conn);
}
}
/**
* 更新区间,乐观策略
* @param dataSource DB来源
* @param tableName 表名
* @param newValue 更新新数据
* @param oldValue 更新旧数据
* @param name 区间名称
* @return 成功/失败
*/
static boolean updateRange(DataSource dataSource, String tableName, Long newValue, Long oldValue, String name) {
Connection conn = null;
PreparedStatement stmt = null;
try {
conn = dataSource.getConnection();
stmt = conn.prepareStatement(SQL_PROVIDER_FACTORY.getUpdateRangeSql().replace("#tableName", tableName));
stmt.setLong(1, newValue);
stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
stmt.setString(3, name);
stmt.setLong(4, oldValue);
int affectedRows = stmt.executeUpdate();
return affectedRows > 0;
}
catch (SQLException e) {
throw new SeqException(e);
}
finally {
closeQuietly(stmt);
closeQuietly(conn);
}
}
/**
* 查询区间,如果区间不存在,会新增一个区间,并返回null,由上层重新执行
* @param dataSource DB来源
* @param tableName 来源
* @param name 区间名称
* @param stepStart 初始位置
* @return 区间值
*/
static Long selectRange(DataSource dataSource, String tableName, String name, long stepStart) {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
long oldValue;
try {
conn = dataSource.getConnection();
stmt = conn.prepareStatement(SQL_PROVIDER_FACTORY.getSelectRangeSql().replace("#tableName", tableName));
stmt.setString(1, name);
rs = stmt.executeQuery();
if (!rs.next()) {
// 没有此类型数据,需要初始化
insertRange(dataSource, tableName, name, stepStart);
return null;
}
oldValue = rs.getLong(1);
if (oldValue < 0) {
String msg = "Sequence value cannot be less than zero, value = " + oldValue
+ ", please check table sequence" + tableName;
throw new SeqException(msg);
}
if (oldValue > Long.MAX_VALUE - DELTA) {
String msg = "Sequence value overflow, value = " + oldValue + ", please check table sequence"
+ tableName;
throw new SeqException(msg);
}
return oldValue;
}
catch (SQLException e) {
throw new SeqException(e);
}
finally {
closeQuietly(rs);
closeQuietly(stmt);
closeQuietly(conn);
}
}
private static void closeQuietly(AutoCloseable closeable) {
if (null != closeable) {
try {
closeable.close();
}
catch (Throwable e) {
// Ignore
}
}
}
public static Boolean existTable(DataSource dataSource, String tableName) {
String existTableSql = SQL_PROVIDER_FACTORY.getExistTableSql();
if (StrUtil.isBlank(existTableSql)) {
return true;
}
Connection conn = null;
Statement stmt = null;
try {
conn = dataSource.getConnection();
stmt = conn.createStatement();
ResultSet resultSet = stmt
.executeQuery(SQL_PROVIDER_FACTORY.getExistTableSql().replace("#tableName", tableName));
if (!resultSet.next()) {
return false;
}
int count = resultSet.getInt(1);
if (0 == count) {
return true;
}
}
catch (SQLException e) {
throw new SeqException(e);
}
finally {
closeQuietly(stmt);
closeQuietly(conn);
}
return false;
}
}
@@ -5,7 +5,6 @@ import com.pig4cloud.pigx.common.sequence.exception.SeqException;
import com.pig4cloud.pigx.common.sequence.range.SeqRange;
import com.pig4cloud.pigx.common.sequence.range.SeqRangeMgr;
import javax.sql.DataSource;
import java.util.concurrent.TimeUnit;
/**
@@ -15,137 +14,117 @@ import java.util.concurrent.TimeUnit;
*/
public class DbSeqRangeMgr implements SeqRangeMgr {
/**
* 区间步长
*/
private int step = 1000;
/**
* 区间步长
*/
private int step = 1000;
/**
* 区间起始位置,真实从stepStart+1开始
*/
private long stepStart = 0;
/**
* 区间起始位置,真实从stepStart+1开始
*/
private long stepStart = 0;
/**
* 获取区间失败重试次数
*/
private int retryTimes = 100;
/**
* 获取区间失败重试次数
*/
private int retryTimes = 100;
/**
* DB来源
*/
private DataSource dataSource;
/**
* 表名,默认range
*/
private String tableName = "range";
/**
* 表名,默认range
*/
private String tableName = "range";
@Override
public SeqRange nextRange(String name) throws SeqException {
if (isEmpty(name)) {
throw new SecurityException("[DbSeqRangeMgr-nextRange] name is empty.");
}
@Override
public SeqRange nextRange(String name) throws SeqException {
if (isEmpty(name)) {
throw new SecurityException("[DbSeqRangeMgr-nextRange] name is empty.");
}
Long oldValue;
Long newValue;
Long oldValue;
Long newValue;
for (int i = 0; i < getRetryTimes(); i++) {
for (int i = 0; i < getRetryTimes(); i++) {
oldValue = BaseDbHelper.selectRange(getDataSource(), getRealTableName(), name, getStepStart());
oldValue = BaseDbHelper.selectRange(getRealTableName(), name, getStepStart());
if (null == oldValue) {
// 区间不存在,重试
continue;
}
if (null == oldValue) {
// 区间不存在,重试
continue;
}
newValue = oldValue + getStep();
newValue = oldValue + getStep();
if (BaseDbHelper.updateRange(getDataSource(), getRealTableName(), newValue, oldValue, name)) {
return new SeqRange(oldValue + 1, newValue);
}
if (BaseDbHelper.updateRange(getRealTableName(), newValue, oldValue, name)) {
return new SeqRange(oldValue + 1, newValue);
}
// else 1秒后 失败重试
ThreadUtil.sleep(1, TimeUnit.SECONDS);
}
// else 1秒后 失败重试
ThreadUtil.sleep(1, TimeUnit.SECONDS);
}
throw new SeqException("Retried too many times, retryTimes = " + getRetryTimes());
}
throw new SeqException("Retried too many times, retryTimes = " + getRetryTimes());
}
@Override
public void init() {
checkParam();
@Override
public void init() {
checkParam();
}
// 判断是否需要创建表
if (BaseDbHelper.existTable(getDataSource(), getRealTableName())) {
BaseDbHelper.createTable(getDataSource(), getRealTableName());
}
}
private boolean isEmpty(String str) {
return null == str || str.trim().isEmpty();
}
private boolean isEmpty(String str) {
return null == str || str.trim().length() == 0;
}
private String getRealTableName() {
return getTableName();
}
private String getRealTableName() {
return getTableName();
}
private void checkParam() {
if (step <= 0) {
throw new SecurityException("[DbSeqRangeMgr-checkParam] step must greater than 0.");
}
if (stepStart < 0) {
throw new SecurityException("[DbSeqRangeMgr-setStepStart] stepStart < 0.");
}
if (retryTimes <= 0) {
throw new SecurityException("[DbSeqRangeMgr-setRetryTimes] retryTimes must greater than 0.");
}
if (isEmpty(tableName)) {
throw new SecurityException("[DbSeqRangeMgr-setTableName] tableName is empty.");
}
}
private void checkParam() {
if (step <= 0) {
throw new SecurityException("[DbSeqRangeMgr-checkParam] step must greater than 0.");
}
if (stepStart < 0) {
throw new SecurityException("[DbSeqRangeMgr-setStepStart] stepStart < 0.");
}
if (retryTimes <= 0) {
throw new SecurityException("[DbSeqRangeMgr-setRetryTimes] retryTimes must greater than 0.");
}
if (null == dataSource) {
throw new SecurityException("[DbSeqRangeMgr-setDataSource] dataSource is null.");
}
if (isEmpty(tableName)) {
throw new SecurityException("[DbSeqRangeMgr-setTableName] tableName is empty.");
}
}
//////// getter and setter
//////// getter and setter
public int getStep() {
return step;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
public void setStep(int step) {
this.step = step;
}
public long getStepStart() {
return stepStart;
}
public long getStepStart() {
return stepStart;
}
public void setStepStart(long stepStart) {
this.stepStart = stepStart;
}
public void setStepStart(long stepStart) {
this.stepStart = stepStart;
}
public int getRetryTimes() {
return retryTimes;
}
public int getRetryTimes() {
return retryTimes;
}
public void setRetryTimes(int retryTimes) {
this.retryTimes = retryTimes;
}
public void setRetryTimes(int retryTimes) {
this.retryTimes = retryTimes;
}
public String getTableName() {
return tableName;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
}
@@ -0,0 +1,30 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import java.time.LocalDateTime;
/**
* 存储序列化的区间
*
* @author lengleng
* @date 2024/6/6
* "CREATE TABLE IF NOT EXISTS #tableName(" + "id bigint(20) NOT NULL AUTO_INCREMENT,"
* + "value bigint(20) NOT NULL," + "name varchar(64) NOT NULL," + "gmt_create DATETIME NOT NULL,"
* + "gmt_modified DATETIME NOT NULL," + "PRIMARY KEY (`id`),UNIQUE uk_name (`name`)" + ")";
*/
@Data
@FieldNameConstants
public class SequenceTable {
private Long id;
private Long value;
private String name;
private LocalDateTime gmtCreate;
private LocalDateTime gmtModified;
}
@@ -1,42 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.stereotype.Component;
/**
* 数据源提供者
*
* @author 达梦数据库支持
* @date 2022-04-27
*
* sql server
*/
@Component
public class DmSqlProvider implements SqlProvider {
/**
* 获取表是否存在
* @return
*/
@Override
public String getExistTableSql() {
return "select count(*) from user_tables where table_name =upper('#tableName')";
}
/**
* 获取建表语句
* @return
*/
@Override
public String getCreateTableSql() {
return "CREATE TABLE #tableName (ID BIGINT NOT NULL,VALUE BIGINT NOT NULL"
+ ",NAME VARCHAR (64) NOT NULL,GMT_CREATE TIMESTAMP (0) NOT NULL,GMT_MODIFIED TIMESTAMP (0) NOT NULL"
+ ",NOT CLUSTER PRIMARY KEY (ID),CONSTRAINT UK_NAME UNIQUE (NAME)) STORAGE (ON MAIN,CLUSTERBTR);";
}
@Override
public Boolean support(DbType dbType) {
return DbType.DM.equals(dbType);
}
}
@@ -1,31 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.stereotype.Component;
/**
* 瀚高数据源
*
* @author lengleng
* @date 2023-04-26
*/
@Component
public class HighGoSqlProvider implements SqlProvider {
/**
* 获取建表语句
* @return
*/
@Override
public String getCreateTableSql() {
return "CREATE TABLE IF NOT EXISTS #tableName (ID int8 PRIMARY KEY NOT NULL"
+ ",VALUE int8 NOT NULL,NAME VARCHAR (266) NOT NULL,gmt_create TIMESTAMP (6) NOT NULL"
+ ",gmt_modified TIMESTAMP (6) NOT NULL)";
}
@Override
public Boolean support(DbType dbType) {
return DbType.HIGH_GO.equals(dbType);
}
}
@@ -1,27 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.stereotype.Component;
/**
* @author lengleng
* @date 2023/4/23 kingbase数据库支持
*/
@Component
public class KingbaseSqlProvider implements SqlProvider {
/**
* 获取建表语句
* @return SQL
*/
@Override
public String getCreateTableSql() {
return "CREATE TABLE IF NOT EXISTS #tableName (ID INT8 PRIMARY KEY NOT NULL,VALUE INT8 NOT NULL,NAME VARCHAR (266) NOT NULL,gmt_create TIMESTAMP (6) NOT NULL,gmt_modified TIMESTAMP (6) NOT NULL)";
}
@Override
public Boolean support(DbType dbType) {
return DbType.KINGBASE_ES.equals(dbType);
}
}
@@ -1,34 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.stereotype.Component;
/**
* 数据源提供者
*
* @author hanyichao
* @date 2022-04-27
*
* sql server
*/
@Component
public class MssqlSqlProvider implements SqlProvider {
/**
* 获取建表语句
* @return
*/
@Override
public String getCreateTableSql() {
return "IF NOT EXISTS (\n"
+ "SELECT*FROM sys.all_objects WHERE object_id=OBJECT_ID(N'#tableName') AND type IN ('U')) \n"
+ "CREATE TABLE #tableName (id bigint NOT NULL,VALUE bigint NOT NULL,name nvarchar (64) COLLATE "
+ "Chinese_PRC_CI_AS NOT NULL,gmt_create datetime2 (7) NOT NULL,gmt_modified datetime2 (7) NOT NULL) GO";
}
@Override
public Boolean support(DbType dbType) {
return DbType.SQL_SERVER2005.equals(dbType);
}
}
@@ -1,31 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.stereotype.Component;
/**
* 数据源提供者
*
* @author lishangbu
* @date 2021/12/29
*/
@Component
public class MysqlSqlProvider implements SqlProvider {
/**
* 获取建表语句
* @return
*/
@Override
public String getCreateTableSql() {
return "CREATE TABLE IF NOT EXISTS #tableName(" + "id bigint(20) NOT NULL AUTO_INCREMENT,"
+ "value bigint(20) NOT NULL," + "name varchar(64) NOT NULL," + "gmt_create DATETIME NOT NULL,"
+ "gmt_modified DATETIME NOT NULL," + "PRIMARY KEY (`id`),UNIQUE uk_name (`name`)" + ")";
}
@Override
public Boolean support(DbType dbType) {
return DbType.MYSQL.equals(dbType);
}
}
@@ -1,56 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.stereotype.Component;
/**
* oracle数据源
*
* @author lishangbu
* @date 2021/12/29
*/
@Component
public class OracleSqlProvider implements SqlProvider {
/**
* 获取表是否存在
* @return
*/
@Override
public String getExistTableSql() {
return "select count(*) from user_tables where table_name =upper('#tableName')";
}
/**
* 获取建表语句
* @return SQL
*/
@Override
public String getCreateTableSql() {
return "CREATE TABLE #tableName " + "(id NUMBER (20,0) VISIBLE NOT NULL,value NUMBER (20,0) VISIBLE NOT NULL"
+ ",name VARCHAR2 (96 BYTE) VISIBLE,gmt_create DATE VISIBLE NOT NULL"
+ ",gmt_modified DATE VISIBLE NOT NULL)";
}
/**
* 获取更新范围语句
* @return
*/
public String getUpdateRangeSql() {
return "UPDATE #tableName SET value=?,gmt_modified=? WHERE name=? AND value=?";
}
/**
* 获取查询范围语句
* @return
*/
public String getSelectRangeSql() {
return "SELECT value FROM #tableName WHERE name=?";
}
@Override
public Boolean support(DbType dbType) {
return DbType.ORACLE.equals(dbType);
}
}
@@ -1,31 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.stereotype.Component;
/**
* 数据源提供者
*
* @author lengleng
* @date 2022-01-13
*/
@Component
public class PostgreSqlProvider implements SqlProvider {
/**
* 获取建表语句
* @return
*/
@Override
public String getCreateTableSql() {
return "CREATE TABLE IF NOT EXISTS #tableName (ID int8 PRIMARY KEY NOT NULL"
+ ",VALUE int8 NOT NULL,NAME VARCHAR (266) NOT NULL,gmt_create TIMESTAMP (6) NOT NULL"
+ ",gmt_modified TIMESTAMP (6) NOT NULL)";
}
@Override
public Boolean support(DbType dbType) {
return DbType.POSTGRE_SQL.equals(dbType);
}
}
@@ -1,53 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import com.baomidou.mybatisplus.annotation.DbType;
/**
* 数据源提供者
*
* @author lishangbu
* @date 2021/12/29
*/
public interface SqlProvider {
/**
* 获取表是否存在
* @return
*/
default String getExistTableSql() {
return null;
}
/**
* 获取建表语句
* @return
*/
String getCreateTableSql();
/**
* 获取插入范围语句
* @return
*/
default String getInsertRangeSql() {
return "INSERT INTO #tableName (id,name,value,gmt_create,gmt_modified)" + " VALUES(?,?,?,?,?)";
}
/**
* 获取更新范围语句
* @return
*/
default String getUpdateRangeSql() {
return "UPDATE #tableName SET value=?,gmt_modified=? WHERE name=? AND value=?";
}
/**
* 获取查询范围语句
* @return
*/
default String getSelectRangeSql() {
return "SELECT value FROM #tableName WHERE name=?";
}
Boolean support(DbType dbType);
}
@@ -1,101 +0,0 @@
package com.pig4cloud.pigx.common.sequence.range.impl.db.provider;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
import com.pig4cloud.pigx.common.sequence.properties.SequenceDbProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* sql语句提供工厂
*
* @author lishangbu
* @date 2021/12/29
*/
@Lazy(value = false)
@Component
@RequiredArgsConstructor
public class SqlProviderFactory {
private final SequenceDbProperties dbProperties;
private final List<SqlProvider> sqlProviders;
private final Environment environment;
public SqlProvider getSqlProvider() {
DbType dbType = null;
String url = environment.getProperty("spring.datasource.druid.url");
if (StrUtil.isNotBlank(url)) {
dbType = JdbcUtils.getDbType(url);
}
if (dbType == null) {
dbType = dbProperties.getDbType();
}
for (SqlProvider sqlProvider : sqlProviders) {
if (sqlProvider.support(dbType)) {
return sqlProvider;
}
}
throw new UnsupportedOperationException("不支持的数据源");
}
/**
* 获取插入范围语句
*
* @return 插入范围语句
*/
public String getCreateTableSql() {
SqlProvider sqlProvider = getSqlProvider();
return sqlProvider.getCreateTableSql();
}
/**
* 获取插入范围语句
*
* @return 插入范围语句
*/
public String getInsertRangeSql() {
SqlProvider sqlProvider = getSqlProvider();
return sqlProvider.getInsertRangeSql();
}
/**
* 获取查询范围语句
*
* @return
*/
public String getSelectRangeSql() {
SqlProvider sqlProvider = getSqlProvider();
return sqlProvider.getSelectRangeSql();
}
/**
* 获取更新范围语句
*
* @return 更新范围语句
*/
public String getUpdateRangeSql() {
SqlProvider sqlProvider = getSqlProvider();
return sqlProvider.getUpdateRangeSql();
}
/**
* 获取是否创建表语句
*
* @return SQL语句
*/
public String getExistTableSql() {
SqlProvider sqlProvider = getSqlProvider();
return sqlProvider.getExistTableSql();
}
}
@@ -1,10 +1,9 @@
package com.pig4cloud.pigx.common.sequence.range.impl.redis;
import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pigx.common.sequence.exception.SeqException;
import com.pig4cloud.pigx.common.sequence.range.SeqRange;
import com.pig4cloud.pigx.common.sequence.range.SeqRangeMgr;
import redis.clients.jedis.Jedis;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* Redis区间管理器
@@ -13,126 +12,69 @@ import redis.clients.jedis.Jedis;
*/
public class RedisSeqRangeMgr implements SeqRangeMgr {
/**
* 前缀防止key重复
*/
private final static String KEY_PREFIX = "x_sequence_";
/**
* 前缀防止key重复
*/
private final static String KEY_PREFIX = "x_sequence_";
/**
* redis客户端
*/
private Jedis jedis;
/**
* redis客户端
*/
private StringRedisTemplate stringRedisTemplate;
/**
* IP
*/
private String ip;
/**
* 区间步长
*/
private int step = 1000;
/**
* PORT
*/
private Integer port;
/**
* 区间起始位置,真实从stepStart+1开始
*/
private long stepStart = 0;
/**
* 验证权限
*/
private String auth;
/**
* 标记业务key是否存在,如果false,在取nextRange时,会取check一把 这个boolean只为提高性能,不用每次都取redis check
*/
private volatile boolean keyAlreadyExist;
/**
* 区间步长
*/
private int step = 1000;
@Override
public SeqRange nextRange(String name) throws SeqException {
if (!keyAlreadyExist) {
/**
* 区间起始位置,真实从stepStart+1开始
*/
private long stepStart = 0;
if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(getRealKey(name)))) {
// 第一次不存在,进行初始化,setnx不存在就set,存在就忽略
stringRedisTemplate.opsForValue().setIfAbsent(getRealKey(name), String.valueOf(stepStart));
}
keyAlreadyExist = true;
}
/**
* 标记业务key是否存在,如果false,在取nextRange时,会取check一把 这个boolean只为提高性能,不用每次都取redis check
*/
private volatile boolean keyAlreadyExist;
Long max = stringRedisTemplate.opsForValue().increment(getRealKey(name), step);
Long min = max - step + 1;
return new SeqRange(min, max);
}
@Override
public SeqRange nextRange(String name) throws SeqException {
if (!keyAlreadyExist) {
Boolean isExists = jedis.exists(getRealKey(name));
if (!isExists) {
// 第一次不存在,进行初始化,setnx不存在就set,存在就忽略
jedis.setnx(getRealKey(name), String.valueOf(stepStart));
}
keyAlreadyExist = true;
}
Long max = jedis.incrBy(getRealKey(name), step);
Long min = max - step + 1;
return new SeqRange(min, max);
}
private String getRealKey(String name) {
return KEY_PREFIX + name;
}
@Override
public void init() {
checkParam();
jedis = new Jedis(ip, port);
if (StrUtil.isNotBlank(auth)) {
jedis.auth(auth);
}
}
private boolean isEmpty(String str) {
return null == str || str.trim().length() == 0;
}
private void checkParam() {
if (isEmpty(ip)) {
throw new SecurityException("[RedisSeqRangeMgr-checkParam] ip is empty.");
}
if (null == port) {
throw new SecurityException("[RedisSeqRangeMgr-checkParam] port is null.");
}
}
public long getStepStart() {
return stepStart;
}
private String getRealKey(String name) {
return KEY_PREFIX + name;
}
public void setStepStart(long stepStart) {
this.stepStart = stepStart;
}
private boolean isEmpty(String str) {
return null == str || str.trim().length() == 0;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
public String getAuth() {
return auth;
}
public void setAuth(String auth) {
this.auth = auth;
}
public long getStepStart() {
return stepStart;
}
public void setStepStart(long stepStart) {
this.stepStart = stepStart;
}
public StringRedisTemplate getStringRedisTemplate() {
return stringRedisTemplate;
}
public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
}
@@ -110,6 +110,10 @@ public class DefaultRangeSequence implements RangeSequence {
this.seqRangeMgr = seqRangeMgr;
}
public SeqRangeMgr getSeqRangeMgr() {
return seqRangeMgr;
}
@Override
public void setName(BizName name) {
this.bizName = name;