10 Commits

Author SHA1 Message Date
杨黄林
0c737b5449 版本号更新为1.13.1 2026-02-28 14:05:57 +08:00
杨黄林
9a018b6af9 修复达梦数据库下自动创建表时不会自动变更更新时间问题 2026-02-28 14:03:58 +08:00
杨黄林
64724de96c 修复pgsql自动创建sql失败问题 2026-01-14 17:45:36 +08:00
杨黄林
8321032918 去掉GBase8c,这个没自己的连接,它的连接是pgsql 2026-01-14 16:42:19 +08:00
杨黄林
28b95468a3 版本号升级到1.13.0 2026-01-14 14:01:34 +08:00
杨黄林
828a7395d2 增加南大通用GBase8c 2026-01-14 14:01:19 +08:00
20ddc4412e 精简代码 2025-06-05 13:17:38 +08:00
c65bd7b36f 代码优化 2025-06-05 12:59:32 +08:00
721cd48d96 支持达梦数据库V8 2025-06-05 12:58:18 +08:00
e2e5939810 新增 支持达梦数据库
新增 Sequences 增加 updateTime
新增 增加查询序号是否锁定的方法 locked
新增 增加将序号设为未使用的方法 unused
新增 增加 SequencesUnlock find(SequencesUnlock sequencesUnlock) 和 SequencesUnused find(SequencesUnused sequencesUnused)
2025-01-15 11:42:46 +08:00
22 changed files with 304 additions and 43 deletions

View File

@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.yanghuanglin</groupId> <groupId>com.yanghuanglin</groupId>
<artifactId>seq</artifactId> <artifactId>seq</artifactId>
<version>1.10.0</version> <version>1.13.1</version>
<name>seq</name> <name>seq</name>
<description>seq</description> <description>seq</description>
<properties> <properties>
@@ -34,6 +34,12 @@
<version>42.7.3</version> <version>42.7.3</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId>
<version>8.1.3.140</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View File

@@ -3,6 +3,7 @@ package com.yanghuanglin.seq.config;
import com.yanghuanglin.seq.enums.DbType; import com.yanghuanglin.seq.enums.DbType;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
/** /**
@@ -133,7 +134,8 @@ public class GeneratorConfig {
public DbType getDbType() { public DbType getDbType() {
if (this.dbType == null) { if (this.dbType == null) {
try { try {
String productName = this.dataSource.getConnection().getMetaData().getDatabaseProductName(); Connection connection = dataSource.getConnection();
String productName = connection.getMetaData().getDatabaseProductName();
this.dbType = DbType.of(productName); this.dbType = DbType.of(productName);
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException("获取数据库类型失败", e); throw new RuntimeException("获取数据库类型失败", e);

View File

@@ -32,6 +32,11 @@ public class TableConfig {
*/ */
private String createTimeColumn = "create_time"; private String createTimeColumn = "create_time";
/**
* 序号表中最后使用时间
*/
private String updateTimeColumn = "update_time";
public String getTable() { public String getTable() {
return table; return table;
} }
@@ -71,4 +76,12 @@ public class TableConfig {
public void setCreateTimeColumn(String createTimeColumn) { public void setCreateTimeColumn(String createTimeColumn) {
this.createTimeColumn = createTimeColumn.toLowerCase(); this.createTimeColumn = createTimeColumn.toLowerCase();
} }
public String getUpdateTimeColumn() {
return updateTimeColumn;
}
public void setUpdateTimeColumn(String updateTimeColumn) {
this.updateTimeColumn = updateTimeColumn;
}
} }

View File

@@ -10,6 +10,11 @@ import java.util.List;
* @since 2022/1/28 * @since 2022/1/28
*/ */
public interface SequencesUnlockDao { public interface SequencesUnlockDao {
/**
* 查找某个未被锁定的序号
*/
SequencesUnlock find(SequencesUnlock sequencesUnlock);
/** /**
* 保存使用中的序号 * 保存使用中的序号
*/ */

View File

@@ -11,6 +11,11 @@ import java.util.List;
*/ */
public interface SequencesUnusedDao { public interface SequencesUnusedDao {
/**
* 查找某个未被使用的序号
*/
SequencesUnused find(SequencesUnused sequencesUnused);
/** /**
* 根据keytype查找seq最小的空闲序号 * 根据keytype查找seq最小的空闲序号
*/ */

View File

@@ -7,10 +7,12 @@ import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects;
public abstract class SequencesBase { public abstract class SequencesBase {
protected DbType dbType; protected DbType dbType;
@@ -49,6 +51,7 @@ public abstract class SequencesBase {
sql = sql.replaceAll("`seq`", String.format("`%s`", tableConfig.getSeqColumn())); sql = sql.replaceAll("`seq`", String.format("`%s`", tableConfig.getSeqColumn()));
sql = sql.replaceAll("`create_time`", String.format("`%s`", tableConfig.getCreateTimeColumn())); sql = sql.replaceAll("`create_time`", String.format("`%s`", tableConfig.getCreateTimeColumn()));
break; break;
case DM_DBMS:
case PostgreSQL: case PostgreSQL:
case KingbaseES: case KingbaseES:
sql = sql.replaceAll("\"sequences(_unused|_unlock)\"", String.format("%s$1", tableConfig.getTable())); sql = sql.replaceAll("\"sequences(_unused|_unlock)\"", String.format("%s$1", tableConfig.getTable()));
@@ -60,6 +63,13 @@ public abstract class SequencesBase {
} }
InputStream inputStream = new ByteArrayInputStream(sql.getBytes(StandardCharsets.UTF_8)); InputStream inputStream = new ByteArrayInputStream(sql.getBytes(StandardCharsets.UTF_8));
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(new InputStreamResource(inputStream)); ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(new InputStreamResource(inputStream));
if (Objects.equals(dbType.getSeries(), DbType.DM_DBMS.getSeries()) && fileName.endsWith("trigger.sql")) {
// 触发器文件不要通过;分隔,整个文件一起执行
databasePopulator.setSeparator(ScriptUtils.EOF_STATEMENT_SEPARATOR);
} else if (Objects.equals(dbType.getSeries(), DbType.PostgreSQL.getSeries()) && fileName.endsWith("function.sql")) {
// 函数文件不要通过;分隔,整个文件一起执行
databasePopulator.setSeparator(ScriptUtils.EOF_STATEMENT_SEPARATOR);
}
databasePopulator.execute(dataSource); databasePopulator.execute(dataSource);
} catch (IOException e) { } catch (IOException e) {
System.err.println("执行SQL文件" + fileName + "失败"); System.err.println("执行SQL文件" + fileName + "失败");
@@ -72,11 +82,12 @@ public abstract class SequencesBase {
* @param sqlString sql语句 * @param sqlString sql语句
* @return 处理后的语句 * @return 处理后的语句
*/ */
protected String adapter(String sqlString) { protected String dbAdapter(String sqlString) {
switch (dbType) { switch (dbType) {
case MySQL: case MySQL:
break; break;
case PostgreSQL: case PostgreSQL:
case DM_DBMS:
case KingbaseES: case KingbaseES:
sqlString = sqlString.replaceAll("`(.+?)`", "\"$1\""); sqlString = sqlString.replaceAll("`(.+?)`", "\"$1\"");
break; break;

View File

@@ -7,12 +7,14 @@ import com.yanghuanglin.seq.po.Sequences;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import java.util.Objects;
/** /**
* @author yanghuanglin * @author yanghuanglin
* @since 2022/1/28 * @since 2022/1/28
*/ */
@SuppressWarnings("SqlResolve") @SuppressWarnings({"SqlResolve", "SqlSourceToSinkFlow"})
public class SequencesDaoImpl extends SequencesBase implements SequencesDao { public class SequencesDaoImpl extends SequencesBase implements SequencesDao {
public SequencesDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType dbType) { public SequencesDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType dbType) {
@@ -24,11 +26,12 @@ public class SequencesDaoImpl extends SequencesBase implements SequencesDao {
String sql = "select * from `%s` where `%s`=? and `%s`=?"; String sql = "select * from `%s` where `%s`=? and `%s`=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn());
try { try {
return this.jdbcTemplate.queryForObject(adapter(sql), (rs, rowNum) -> { return this.jdbcTemplate.queryForObject(dbAdapter(sql), (rs, rowNum) -> {
Sequences result = new Sequences(); Sequences result = new Sequences();
result.setKey(rs.getString(tableConfig.getKeyColumn())); result.setKey(rs.getString(tableConfig.getKeyColumn()));
result.setType(rs.getString(tableConfig.getTypeColumn())); result.setType(rs.getString(tableConfig.getTypeColumn()));
result.setSeq(rs.getLong(tableConfig.getSeqColumn())); result.setSeq(rs.getLong(tableConfig.getSeqColumn()));
result.setUpdateTime(rs.getDate(tableConfig.getUpdateTimeColumn()));
return result; return result;
}, sequences.getKey(), sequences.getType()); }, sequences.getKey(), sequences.getType());
} catch (EmptyResultDataAccessException ignored) { } catch (EmptyResultDataAccessException ignored) {
@@ -40,7 +43,7 @@ public class SequencesDaoImpl extends SequencesBase implements SequencesDao {
public boolean save(Sequences sequences) { public boolean save(Sequences sequences) {
String sql = "insert into `%s`(`%s`,`%s`,`%s`) values(?,?,?)"; String sql = "insert into `%s`(`%s`,`%s`,`%s`) values(?,?,?)";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
int result = this.jdbcTemplate.update(adapter(sql), sequences.getKey(), sequences.getType(), sequences.getSeq()); int result = this.jdbcTemplate.update(dbAdapter(sql), sequences.getKey(), sequences.getType(), sequences.getSeq());
return result != 0; return result != 0;
} }
@@ -48,12 +51,18 @@ public class SequencesDaoImpl extends SequencesBase implements SequencesDao {
public boolean update(Sequences sequences) { public boolean update(Sequences sequences) {
String sql = "update `%s` set `%s`=? where `%s`=? and `%s`=?"; String sql = "update `%s` set `%s`=? where `%s`=? and `%s`=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getSeqColumn(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getSeqColumn(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn());
int result = this.jdbcTemplate.update(adapter(sql), sequences.getSeq(), sequences.getKey(), sequences.getType()); int result = this.jdbcTemplate.update(dbAdapter(sql), sequences.getSeq(), sequences.getKey(), sequences.getType());
return result != 0; return result != 0;
} }
@Override @Override
public void createTable() { public void createTable() {
this.createTableByFile("create_table_sequences.sql"); this.createTableByFile("create_table_sequences.sql");
if (Objects.equals(dbType.getSeries(), DbType.DM_DBMS.getSeries())) {
this.createTableByFile("create_table_sequences_trigger.sql");
} else if (Objects.equals(dbType.getSeries(), DbType.PostgreSQL.getSeries())) {
this.createTableByFile("create_table_sequences_function.sql");
this.createTableByFile("create_table_sequences_trigger.sql");
}
} }
} }

View File

@@ -4,6 +4,7 @@ import com.yanghuanglin.seq.config.TableConfig;
import com.yanghuanglin.seq.dao.SequencesUnlockDao; import com.yanghuanglin.seq.dao.SequencesUnlockDao;
import com.yanghuanglin.seq.enums.DbType; import com.yanghuanglin.seq.enums.DbType;
import com.yanghuanglin.seq.po.SequencesUnlock; import com.yanghuanglin.seq.po.SequencesUnlock;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
@@ -14,18 +15,36 @@ import java.util.List;
* @author yanghuanglin * @author yanghuanglin
* @since 2022/1/28 * @since 2022/1/28
*/ */
@SuppressWarnings("SqlResolve") @SuppressWarnings({"SqlResolve", "SqlSourceToSinkFlow"})
public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUnlockDao { public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUnlockDao {
public SequencesUnlockDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType dbType) { public SequencesUnlockDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType dbType) {
super(jdbcTemplate, tableConfig, dbType); super(jdbcTemplate, tableConfig, dbType);
} }
@Override
public SequencesUnlock find(SequencesUnlock sequencesUnlock) {
String sql = "select * from `%s_unlock` where `%s`=? and `%s`=? and `%s`=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
try {
return this.jdbcTemplate.queryForObject(dbAdapter(sql), (rs, rowNum) -> {
SequencesUnlock result = new SequencesUnlock();
result.setKey(rs.getString(tableConfig.getKeyColumn()));
result.setType(rs.getString(tableConfig.getTypeColumn()));
result.setSeq(rs.getLong(tableConfig.getSeqColumn()));
result.setCreateTime(rs.getDate(tableConfig.getCreateTimeColumn()));
return result;
}, sequencesUnlock.getKey(), sequencesUnlock.getType(), sequencesUnlock.getSeq());
} catch (EmptyResultDataAccessException ignored) {
return null;
}
}
@Override @Override
public boolean save(SequencesUnlock sequencesUnlock) { public boolean save(SequencesUnlock sequencesUnlock) {
String sql = "insert into `%s_unlock`(`%s`,`%s`,`%s`,`%s`) values(?,?,?,?)"; 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()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn(), tableConfig.getCreateTimeColumn());
int result = this.jdbcTemplate.update(adapter(sql), sequencesUnlock.getKey(), sequencesUnlock.getType(), sequencesUnlock.getSeq(), sequencesUnlock.getCreateTime()); int result = this.jdbcTemplate.update(dbAdapter(sql), sequencesUnlock.getKey(), sequencesUnlock.getType(), sequencesUnlock.getSeq(), sequencesUnlock.getCreateTime());
return result != 0; return result != 0;
} }
@@ -36,9 +55,9 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn
if (sequencesUnlock.getSeq() != null) { if (sequencesUnlock.getSeq() != null) {
sql += " and `%s`=?"; sql += " and `%s`=?";
sql = String.format(sql, tableConfig.getSeqColumn()); sql = String.format(sql, tableConfig.getSeqColumn());
return this.jdbcTemplate.update(adapter(sql), sequencesUnlock.getKey(), sequencesUnlock.getType(), sequencesUnlock.getSeq()) != 0; return this.jdbcTemplate.update(dbAdapter(sql), sequencesUnlock.getKey(), sequencesUnlock.getType(), sequencesUnlock.getSeq()) != 0;
} else { } else {
return this.jdbcTemplate.update(adapter(sql), sequencesUnlock.getKey(), sequencesUnlock.getType()) != 0; return this.jdbcTemplate.update(dbAdapter(sql), sequencesUnlock.getKey(), sequencesUnlock.getType()) != 0;
} }
} }
@@ -46,7 +65,7 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn
public List<SequencesUnlock> listAll() { public List<SequencesUnlock> listAll() {
String sql = "select * from `%s_unlock`"; String sql = "select * from `%s_unlock`";
sql = String.format(sql, tableConfig.getTable()); sql = String.format(sql, tableConfig.getTable());
return this.jdbcTemplate.query(adapter(sql), rowMapper()); return this.jdbcTemplate.query(dbAdapter(sql), rowMapper());
} }
@Override @Override
@@ -55,15 +74,15 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn
if (begin != null && end != null) { if (begin != null && end != null) {
sql = "select * from `%s_unlock` where `%s`>=? and `%s`<=?"; sql = "select * from `%s_unlock` where `%s`>=? and `%s`<=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.query(adapter(sql), rowMapper(), begin, end); return this.jdbcTemplate.query(dbAdapter(sql), rowMapper(), begin, end);
} else if (begin != null) { } else if (begin != null) {
sql = "select * from `%s_unlock` where `%s`>=?"; sql = "select * from `%s_unlock` where `%s`>=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.query(adapter(sql), rowMapper(), begin); return this.jdbcTemplate.query(dbAdapter(sql), rowMapper(), begin);
} else if (end != null) { } else if (end != null) {
sql = "select * from `%s_unlock` where `%s`<=?"; sql = "select * from `%s_unlock` where `%s`<=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.query(adapter(sql), rowMapper(), end); return this.jdbcTemplate.query(dbAdapter(sql), rowMapper(), end);
} else { } else {
return listAll(); return listAll();
} }
@@ -73,7 +92,7 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn
public boolean deleteAll() { public boolean deleteAll() {
String sql = "delete from `%s_unlock`"; String sql = "delete from `%s_unlock`";
sql = String.format(sql, tableConfig.getTable()); sql = String.format(sql, tableConfig.getTable());
int result = this.jdbcTemplate.update(adapter(sql)); int result = this.jdbcTemplate.update(dbAdapter(sql));
return result != 0; return result != 0;
} }
@@ -83,15 +102,15 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn
if (begin != null && end != null) { if (begin != null && end != null) {
sql = "delete from `%s_unlock` where `%s`>=? and `%s`<=?"; sql = "delete from `%s_unlock` where `%s`>=? and `%s`<=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.update(adapter(sql), begin, end) != 0; return this.jdbcTemplate.update(dbAdapter(sql), begin, end) != 0;
} else if (begin != null) { } else if (begin != null) {
sql = "delete from `%s_unlock` where `%s`>=?"; sql = "delete from `%s_unlock` where `%s`>=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.update(adapter(sql), begin) != 0; return this.jdbcTemplate.update(dbAdapter(sql), begin) != 0;
} else if (end != null) { } else if (end != null) {
sql = "delete from `%s_unlock` where `%s`<=?"; sql = "delete from `%s_unlock` where `%s`<=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.update(adapter(sql), end) != 0; return this.jdbcTemplate.update(dbAdapter(sql), end) != 0;
} else { } else {
return deleteAll(); return deleteAll();
} }

View File

@@ -19,19 +19,37 @@ import java.util.List;
* @author yanghuanglin * @author yanghuanglin
* @since 2022/1/28 * @since 2022/1/28
*/ */
@SuppressWarnings("SqlResolve") @SuppressWarnings({"SqlResolve", "SqlSourceToSinkFlow"})
public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUnusedDao { public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUnusedDao {
public SequencesUnusedDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType dbType) { public SequencesUnusedDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType dbType) {
super(jdbcTemplate, tableConfig, dbType); super(jdbcTemplate, tableConfig, dbType);
} }
@Override
public SequencesUnused find(SequencesUnused sequencesUnused) {
String sql = "select * from `%s_unused` where `%s`=? and `%s`=? and `%s`=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
try {
return this.jdbcTemplate.queryForObject(dbAdapter(sql), (rs, rowNum) -> {
SequencesUnused result = new SequencesUnused();
result.setKey(rs.getString(tableConfig.getKeyColumn()));
result.setType(rs.getString(tableConfig.getTypeColumn()));
result.setSeq(rs.getLong(tableConfig.getSeqColumn()));
result.setCreateTime(rs.getDate(tableConfig.getCreateTimeColumn()));
return result;
}, sequencesUnused.getKey(), sequencesUnused.getType(), sequencesUnused.getSeq());
} catch (EmptyResultDataAccessException ignored) {
return null;
}
}
@Override @Override
public SequencesUnused findMinSeq(SequencesUnused sequencesUnused) { public SequencesUnused findMinSeq(SequencesUnused sequencesUnused) {
String sql = "select * from `%s_unused` where `%s`=? and `%s`=? order by `%s` asc limit 0,1"; String sql = "select * from `%s_unused` where `%s`=? and `%s`=? order by `%s` asc limit 0,1";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
try { try {
return this.jdbcTemplate.queryForObject(adapter(sql), rowMapper(), sequencesUnused.getKey(), sequencesUnused.getType()); return this.jdbcTemplate.queryForObject(dbAdapter(sql), rowMapper(), sequencesUnused.getKey(), sequencesUnused.getType());
} catch (EmptyResultDataAccessException ignored) { } catch (EmptyResultDataAccessException ignored) {
return null; return null;
} }
@@ -42,7 +60,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn
try { try {
String sql = "select * from `%s_unused` where `%s`=? and `%s`=? order by `%s` desc limit 0,1"; String sql = "select * from `%s_unused` where `%s`=? and `%s`=? order by `%s` desc limit 0,1";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
return this.jdbcTemplate.queryForObject(adapter(sql), rowMapper(), sequencesUnused.getKey(), sequencesUnused.getType()); return this.jdbcTemplate.queryForObject(dbAdapter(sql), rowMapper(), sequencesUnused.getKey(), sequencesUnused.getType());
} catch (EmptyResultDataAccessException ignored) { } catch (EmptyResultDataAccessException ignored) {
return null; return null;
} }
@@ -52,7 +70,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn
public boolean delete(SequencesUnused sequencesUnused) { public boolean delete(SequencesUnused sequencesUnused) {
String sql = "delete from `%s_unused` where `%s`=? and `%s`=? and `%s`=?"; String sql = "delete from `%s_unused` where `%s`=? and `%s`=? and `%s`=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn());
int result = this.jdbcTemplate.update(adapter(sql), sequencesUnused.getKey(), sequencesUnused.getType(), sequencesUnused.getSeq()); int result = this.jdbcTemplate.update(dbAdapter(sql), sequencesUnused.getKey(), sequencesUnused.getType(), sequencesUnused.getSeq());
return result != 0; return result != 0;
} }
@@ -60,7 +78,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn
public boolean save(SequencesUnused sequencesUnused) { public boolean save(SequencesUnused sequencesUnused) {
String sql = "insert into `%s_unused`(`%s`,`%s`,`%s`,`%s`) values(?,?,?,?)"; String sql = "insert into `%s_unused`(`%s`,`%s`,`%s`,`%s`) values(?,?,?,?)";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn(), tableConfig.getCreateTimeColumn());
int result = this.jdbcTemplate.update(adapter(sql), sequencesUnused.getKey(), sequencesUnused.getType(), sequencesUnused.getSeq(), sequencesUnused.getCreateTime()); int result = this.jdbcTemplate.update(dbAdapter(sql), sequencesUnused.getKey(), sequencesUnused.getType(), sequencesUnused.getSeq(), sequencesUnused.getCreateTime());
return result != 0; return result != 0;
} }
@@ -68,7 +86,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn
public boolean saveBatch(List<SequencesUnused> sequencesUnusedList) { public boolean saveBatch(List<SequencesUnused> sequencesUnusedList) {
String sql = "insert into `%s_unused`(`%s`,`%s`,`%s`,`%s`) values(?,?,?,?)"; String sql = "insert into `%s_unused`(`%s`,`%s`,`%s`,`%s`) values(?,?,?,?)";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn(), tableConfig.getSeqColumn(), tableConfig.getCreateTimeColumn());
int[] result = this.jdbcTemplate.batchUpdate(adapter(sql), new BatchPreparedStatementSetter() { int[] result = this.jdbcTemplate.batchUpdate(dbAdapter(sql), new BatchPreparedStatementSetter() {
@Override @Override
public void setValues(PreparedStatement ps, int i) throws SQLException { public void setValues(PreparedStatement ps, int i) throws SQLException {
SequencesUnused sequencesUnused = sequencesUnusedList.get(i); SequencesUnused sequencesUnused = sequencesUnusedList.get(i);
@@ -95,7 +113,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn
public boolean deleteAll() { public boolean deleteAll() {
String sql = "delete from `%s_unused`"; String sql = "delete from `%s_unused`";
sql = String.format(sql, tableConfig.getTable()); sql = String.format(sql, tableConfig.getTable());
int result = this.jdbcTemplate.update(adapter(sql)); int result = this.jdbcTemplate.update(dbAdapter(sql));
return result != 0; return result != 0;
} }
@@ -105,15 +123,15 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn
if (begin != null && end != null) { if (begin != null && end != null) {
sql = "delete from `%s_unused` where `%s`>=? and `%s`<=?"; sql = "delete from `%s_unused` where `%s`>=? and `%s`<=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.update(adapter(sql), begin, end) != 0; return this.jdbcTemplate.update(dbAdapter(sql), begin, end) != 0;
} else if (begin != null) { } else if (begin != null) {
sql = "delete from `%s_unused` where `%s`>=?"; sql = "delete from `%s_unused` where `%s`>=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.update(adapter(sql), begin) != 0; return this.jdbcTemplate.update(dbAdapter(sql), begin) != 0;
} else if (end != null) { } else if (end != null) {
sql = "delete from `%s_unused` where `%s`<=?"; sql = "delete from `%s_unused` where `%s`<=?";
sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn()); sql = String.format(sql, tableConfig.getTable(), tableConfig.getCreateTimeColumn());
return this.jdbcTemplate.update(adapter(sql), end) != 0; return this.jdbcTemplate.update(dbAdapter(sql), end) != 0;
} else { } else {
return deleteAll(); return deleteAll();
} }

View File

@@ -3,6 +3,8 @@ package com.yanghuanglin.seq.enums;
public enum DbType { public enum DbType {
//MySQL数据库 //MySQL数据库
MySQL("mysql"), MySQL("mysql"),
//达梦数据库
DM_DBMS("dm"),
//人大金仓数据库 //人大金仓数据库
KingbaseES("pgsql"), KingbaseES("pgsql"),
//PostgreSQL数据库 //PostgreSQL数据库
@@ -26,7 +28,7 @@ public enum DbType {
*/ */
public static DbType of(String productName) { public static DbType of(String productName) {
for (DbType value : DbType.values()) { for (DbType value : DbType.values()) {
if (value.name().equalsIgnoreCase(productName)) { if (value.name().equalsIgnoreCase(productName.replace(" ", "_"))) {
return value; return value;
} }
} }

View File

@@ -221,6 +221,14 @@ public interface Generator {
*/ */
Sequences parse(String formatted, String pattern, Integer fixLength); Sequences parse(String formatted, String pattern, Integer fixLength);
/**
* 查询序号是否已被锁定
*
* @param sequences 需要查询的序号
* @return 锁定结果
*/
boolean locked(Sequences sequences);
/** /**
* 锁定指定序号,在序号生成后,调用该序号的逻辑完成后需要执行此方法 * 锁定指定序号,在序号生成后,调用该序号的逻辑完成后需要执行此方法
* <p/> * <p/>
@@ -244,6 +252,14 @@ public interface Generator {
*/ */
boolean lock(Sequences sequences, boolean ignoreSeq); boolean lock(Sequences sequences, boolean ignoreSeq);
/**
* 将序号设为未使用
*
* @param sequences 需要设为未使用的序号
* @return 设置结果
*/
boolean unused(Sequences sequences);
/** /**
* 释放所有未使用的序号 * 释放所有未使用的序号
* <p/> * <p/>

View File

@@ -22,6 +22,7 @@ import java.util.regex.Pattern;
import static com.yanghuanglin.seq.enums.FormatPlaceholder.*; import static com.yanghuanglin.seq.enums.FormatPlaceholder.*;
@SuppressWarnings("CallToPrintStackTrace")
public class SequencesGenerator implements Generator { public class SequencesGenerator implements Generator {
private final TransactionTemplate transactionTemplate; private final TransactionTemplate transactionTemplate;
private final SequencesDao sequencesDao; private final SequencesDao sequencesDao;
@@ -89,7 +90,11 @@ public class SequencesGenerator implements Generator {
//根据传入的key和type新生成查询条件对象 //根据传入的key和type新生成查询条件对象
Sequences condition = new Sequences(key, type); Sequences condition = new Sequences(key, type);
if (!withOutSeq) { if (Boolean.TRUE.equals(withOutSeq)) {
//不包含序号
condition.setWithOutSeq(true);
return condition;
} else {
//不是不包含序号的序号对象(有可能格式中只配置了#year##month##day#,序号就不用自增,也不用入库,直接返回即可) //不是不包含序号的序号对象(有可能格式中只配置了#year##month##day#,序号就不用自增,也不用入库,直接返回即可)
//找到正在使用的最大序号 //找到正在使用的最大序号
Sequences sequences = sequencesDao.find(condition); Sequences sequences = sequencesDao.find(condition);
@@ -123,9 +128,6 @@ public class SequencesGenerator implements Generator {
} }
sequences.setWithOutSeq(false); sequences.setWithOutSeq(false);
return result ? sequences : null; return result ? sequences : null;
} else {
condition.setWithOutSeq(true);
return condition;
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -305,10 +307,30 @@ public class SequencesGenerator implements Generator {
} }
@Override @Override
public synchronized boolean lock(Sequences sequences) { public boolean locked(Sequences sequences) {
if (sequences == null || sequences.getWithOutSeq()) if (sequences == null || Boolean.TRUE.equals(sequences.getWithOutSeq()))
return true; return true;
SequencesUnlock condition = new SequencesUnlock(sequences); SequencesUnlock condition = new SequencesUnlock(sequences);
//将使用中表的对应数据删除,空闲表中数据在生成时会删除,因此这里不需要处理该表
return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
try {
SequencesUnlock sequencesUnlock = sequencesUnlockDao.find(condition);
return sequencesUnlock == null;
} catch (Exception e) {
e.printStackTrace();
status.setRollbackOnly();
return false;
}
}));
}
@Override
public synchronized boolean lock(Sequences sequences) {
if (sequences == null || Boolean.TRUE.equals(sequences.getWithOutSeq()))
return true;
SequencesUnlock condition = new SequencesUnlock(sequences);
//将使用中表的对应数据删除,空闲表中数据在生成时会删除,因此这里不需要处理该表 //将使用中表的对应数据删除,空闲表中数据在生成时会删除,因此这里不需要处理该表
return Boolean.TRUE.equals(transactionTemplate.execute(status -> { return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
try { try {
@@ -325,7 +347,7 @@ public class SequencesGenerator implements Generator {
public synchronized boolean lock(Sequences sequences, boolean ignoreSeq) { public synchronized boolean lock(Sequences sequences, boolean ignoreSeq) {
if (!ignoreSeq) if (!ignoreSeq)
return lock(sequences); return lock(sequences);
if (sequences == null || sequences.getWithOutSeq()) if (sequences == null || Boolean.TRUE.equals(sequences.getWithOutSeq()))
return true; return true;
SequencesUnlock condition = new SequencesUnlock(sequences); SequencesUnlock condition = new SequencesUnlock(sequences);
condition.setSeq(null); condition.setSeq(null);
@@ -341,6 +363,24 @@ public class SequencesGenerator implements Generator {
})); }));
} }
@Override
public boolean unused(Sequences sequences) {
if (sequences == null)
return true;
SequencesUnused condition = new SequencesUnused(sequences);
condition.setCreateTime(new Date());
//在未使用中表增加需要设为未使用的序号
return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
try {
return sequencesUnusedDao.save(condition);
} catch (Exception e) {
e.printStackTrace();
status.setRollbackOnly();
return false;
}
}));
}
@Override @Override
public synchronized boolean release() { public synchronized boolean release() {
//列出所有使用中表存在的序号 //列出所有使用中表存在的序号

View File

@@ -2,6 +2,8 @@ package com.yanghuanglin.seq.po;
import com.yanghuanglin.seq.config.BaseConfig; import com.yanghuanglin.seq.config.BaseConfig;
import java.util.Date;
/** /**
* 当前序号 * 当前序号
* *
@@ -24,6 +26,11 @@ public class Sequences {
*/ */
protected Long seq = 0L; protected Long seq = 0L;
/**
* 最后使用时间
*/
private Date updateTime;
/** /**
* 临时字段序号对应的年份如2022年如果能获取到的话 * 临时字段序号对应的年份如2022年如果能获取到的话
* 该字段仅用于解析序号字符串时解析出对应年份用于合成key序号对应的key为SNT+年份,返回的为其年份) * 该字段仅用于解析序号字符串时解析出对应年份用于合成key序号对应的key为SNT+年份,返回的为其年份)
@@ -101,6 +108,14 @@ public class Sequences {
this.seq = seq; this.seq = seq;
} }
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Integer getYear() { public Integer getYear() {
return year; return year;
} }
@@ -180,10 +195,11 @@ public class Sequences {
"key='" + key + '\'' + "key='" + key + '\'' +
", type='" + type + '\'' + ", type='" + type + '\'' +
", seq=" + seq + ", seq=" + seq +
", updateTime=" + updateTime +
", year=" + year + ", year=" + year +
", month=" + month + ", month=" + month +
", day=" + day + ", day=" + day +
", fix=" + fix + ", fix='" + fix + '\'' +
", withOutSeq=" + withOutSeq + ", withOutSeq=" + withOutSeq +
'}'; '}';
} }

View File

@@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS "sequences"
(
"key" VARCHAR(64) NOT NULL,
"type" VARCHAR(64) NOT NULL,
"seq" BIGINT NOT NULL,
"update_time" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ("key", "type")
);
COMMENT ON TABLE "sequences" IS '当前序号表';
COMMENT ON COLUMN "sequences"."key" IS '序号英文名称';
COMMENT ON COLUMN "sequences"."type" IS '序号类型';
COMMENT ON COLUMN "sequences"."seq" IS '已使用到的序号';
COMMENT ON COLUMN "sequences"."update_time" IS '最后使用时间';

View File

@@ -0,0 +1,8 @@
CREATE OR REPLACE TRIGGER "SEQUENCES_UPDATE_TIME"
BEFORE UPDATE
ON "sequences"
referencing OLD ROW AS "OLD" NEW ROW AS "NEW"
FOR EACH ROW
BEGIN
:NEW."UPDATE_TIME" := CURRENT_TIMESTAMP;
END;

View File

@@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS "sequences_unlock"
(
"key" VARCHAR(64) NOT NULL,
"type" VARCHAR(64) NOT NULL,
"seq" BIGINT NOT NULL,
"create_time" TIMESTAMP NOT NULL,
PRIMARY KEY ("key", "type", "seq")
);
COMMENT ON TABLE "sequences_unlock" IS '未锁定序号表';
COMMENT ON COLUMN "sequences_unlock"."key" IS '序号英文名称';
COMMENT ON COLUMN "sequences_unlock"."type" IS '序号类型';
COMMENT ON COLUMN "sequences_unlock"."seq" IS '尚未锁定的序号';
COMMENT ON COLUMN "sequences_unlock"."create_time" IS '使用时间';

View File

@@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS "sequences_unused"
(
"key" VARCHAR(64) NOT NULL,
"type" VARCHAR(64) NOT NULL,
"seq" BIGINT NOT NULL,
"create_time" TIMESTAMP NOT NULL,
PRIMARY KEY ("key", "type", "seq")
);
COMMENT ON TABLE "sequences_unused" IS '闲置序号表';
COMMENT ON COLUMN "sequences_unused"."key" IS '序号英文名称';
COMMENT ON COLUMN "sequences_unused"."type" IS '序号类型';
COMMENT ON COLUMN "sequences_unused"."seq" IS '闲置的的序号';
COMMENT ON COLUMN "sequences_unused"."create_time" IS '设为闲置序号的时间';

View File

@@ -3,5 +3,6 @@ CREATE TABLE IF NOT EXISTS `sequences`
`key` VARCHAR(64) NOT NULL COMMENT '序号英文名称', `key` VARCHAR(64) NOT NULL COMMENT '序号英文名称',
`type` VARCHAR(64) NOT NULL COMMENT '序号类型', `type` VARCHAR(64) NOT NULL COMMENT '序号类型',
`seq` BIGINT(20) NOT NULL COMMENT '已使用到的序号', `seq` BIGINT(20) NOT NULL COMMENT '已使用到的序号',
`update_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后使用时间',
PRIMARY KEY (`key`, `type`) PRIMARY KEY (`key`, `type`)
) COMMENT '当前序号表'; ) COMMENT '当前序号表';

View File

@@ -1,11 +1,13 @@
CREATE TABLE IF NOT EXISTS "sequences" CREATE TABLE IF NOT EXISTS "sequences"
( (
"key" VARCHAR(64) NOT NULL, "key" VARCHAR(64) NOT NULL,
"type" VARCHAR(64) NOT NULL, "type" VARCHAR(64) NOT NULL,
"seq" INT8 NOT NULL, "seq" INT8 NOT NULL,
"update_time" TIMESTAMP,
PRIMARY KEY ("key", "type") PRIMARY KEY ("key", "type")
); );
COMMENT ON TABLE "sequences" IS '当前序号表'; COMMENT ON TABLE "sequences" IS '当前序号表';
COMMENT ON COLUMN "sequences"."key" IS '序号英文名称'; COMMENT ON COLUMN "sequences"."key" IS '序号英文名称';
COMMENT ON COLUMN "sequences"."type" IS '序号类型'; COMMENT ON COLUMN "sequences"."type" IS '序号类型';
COMMENT ON COLUMN "sequences"."seq" IS '已使用到的序号'; COMMENT ON COLUMN "sequences"."seq" IS '已使用到的序号';
COMMENT ON COLUMN "sequences"."update_time" IS '最后使用时间';

View File

@@ -0,0 +1,6 @@
CREATE OR REPLACE FUNCTION SEQUENCES_UPDATE_TIME() RETURNS TRIGGER AS $$
BEGIN
NEW."update_time" := current_timestamp;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

View File

@@ -0,0 +1,2 @@
DROP TRIGGER IF EXISTS SEQUENCES_UPDATE_TIME ON "sequences" CASCADE;
CREATE TRIGGER SEQUENCES_UPDATE_TIME BEFORE INSERT OR UPDATE ON "sequences" FOR EACH ROW EXECUTE PROCEDURE SEQUENCES_UPDATE_TIME();

View File

@@ -5,10 +5,12 @@ import com.yanghuanglin.seq.config.TableConfig;
import com.yanghuanglin.seq.generator.Generator; import com.yanghuanglin.seq.generator.Generator;
import com.yanghuanglin.seq.generator.impl.SequencesGenerator; import com.yanghuanglin.seq.generator.impl.SequencesGenerator;
import com.yanghuanglin.seq.po.Sequences; import com.yanghuanglin.seq.po.Sequences;
import dm.jdbc.driver.DmdbDataSource;
import org.junit.Test; import org.junit.Test;
import org.postgresql.ds.PGSimpleDataSource; import org.postgresql.ds.PGSimpleDataSource;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.DatabaseMetaData;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
@@ -24,7 +26,7 @@ public class SeqTest {
private static final Generator generator; private static final Generator generator;
static { static {
dataSource = pgsql(); dataSource = dm();
GeneratorConfig generatorConfig = new GeneratorConfig(dataSource); GeneratorConfig generatorConfig = new GeneratorConfig(dataSource);
System.out.println("DbType: " + generatorConfig.getDbType()); System.out.println("DbType: " + generatorConfig.getDbType());
@@ -65,6 +67,14 @@ public class SeqTest {
return pgDataSource; return pgDataSource;
} }
private static DataSource dm() {
DmdbDataSource dmdbDataSource = new DmdbDataSource();
dmdbDataSource.setURL("jdbc:dm://127.0.0.1:5236?schema=sequence");
dmdbDataSource.setUser("SYSDBA");
dmdbDataSource.setPassword("SYSDBA");
return dmdbDataSource;
}
@Test @Test
public void createTable() { public void createTable() {
generator.createTable(); generator.createTable();
@@ -124,4 +134,35 @@ public class SeqTest {
sequences.setType("MISSION"); sequences.setType("MISSION");
System.out.println(sequences); System.out.println(sequences);
} }
@Test
public void unusedTest() {
Sequences sequences = new Sequences();
sequences.setKey("0010001$distrainCode2024");
sequences.setType("MISSION");
sequences.setSeq(1L);
boolean result = generator.unused(sequences);
assert result;
}
@Test
public void lockTest() {
generator.generate("0010001$distrainCode2024","MISSION");
Sequences sequences = new Sequences();
sequences.setKey("0010001$distrainCode2024");
sequences.setType("MISSION");
sequences.setSeq(1L);
boolean result = generator.lock(sequences);
assert result;
}
@Test
public void lockedTest() {
Sequences sequences = new Sequences();
sequences.setKey("0010001$distrainCode2024");
sequences.setType("MISSION");
sequences.setSeq(1L);
boolean result = generator.locked(sequences);
System.out.println("locked: " + result);
}
} }