From e2e5939810eb4a6d5fa1e85e72c580e2c6819768 Mon Sep 17 00:00:00 2001 From: yanghuanglin Date: Wed, 15 Jan 2025 11:42:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=BE=BE=E6=A2=A6=E6=95=B0=E6=8D=AE=E5=BA=93=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20Sequences=20=E5=A2=9E=E5=8A=A0=20updateTime=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=BA=8F=E5=8F=B7=E6=98=AF=E5=90=A6=E9=94=81=E5=AE=9A=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95=20locked=20=E6=96=B0=E5=A2=9E=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=B0=86=E5=BA=8F=E5=8F=B7=E8=AE=BE=E4=B8=BA=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E6=96=B9=E6=B3=95=20unused=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E5=A2=9E=E5=8A=A0=20SequencesUnlock=20fin?= =?UTF-8?q?d(SequencesUnlock=20sequencesUnlock)=20=E5=92=8C=20SequencesUnu?= =?UTF-8?q?sed=20find(SequencesUnused=20sequencesUnused)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../yanghuanglin/seq/config/TableConfig.java | 13 +++++ .../seq/dao/SequencesUnlockDao.java | 5 ++ .../seq/dao/SequencesUnusedDao.java | 5 ++ .../seq/dao/impl/SequencesBase.java | 4 +- .../seq/dao/impl/SequencesDaoImpl.java | 9 ++-- .../seq/dao/impl/SequencesUnlockDaoImpl.java | 43 ++++++++++----- .../seq/dao/impl/SequencesUnusedDaoImpl.java | 38 +++++++++---- .../com/yanghuanglin/seq/enums/DbType.java | 2 + .../yanghuanglin/seq/generator/Generator.java | 16 ++++++ .../generator/impl/SequencesGenerator.java | 54 ++++++++++++++++--- .../com/yanghuanglin/seq/po/Sequences.java | 18 ++++++- .../resources/dm/create_table_sequences.sql | 26 +++++++++ .../dm/create_table_sequences_unlock.sql | 13 +++++ .../dm/create_table_sequences_unused.sql | 13 +++++ .../mysql/create_table_sequences.sql | 1 + .../pgsql/create_table_sequences.sql | 29 ++++++++-- src/test/java/SeqTest.java | 32 ++++++++++- 18 files changed, 282 insertions(+), 41 deletions(-) create mode 100644 src/main/resources/dm/create_table_sequences.sql create mode 100644 src/main/resources/dm/create_table_sequences_unlock.sql create mode 100644 src/main/resources/dm/create_table_sequences_unused.sql diff --git a/pom.xml b/pom.xml index a8d4ce6..9d17db9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.yanghuanglin seq - 1.10.0 + 1.11.0 seq seq diff --git a/src/main/java/com/yanghuanglin/seq/config/TableConfig.java b/src/main/java/com/yanghuanglin/seq/config/TableConfig.java index dbac42a..10705ac 100644 --- a/src/main/java/com/yanghuanglin/seq/config/TableConfig.java +++ b/src/main/java/com/yanghuanglin/seq/config/TableConfig.java @@ -32,6 +32,11 @@ public class TableConfig { */ private String createTimeColumn = "create_time"; + /** + * 序号表中最后使用时间 + */ + private String updateTimeColumn = "update_time"; + public String getTable() { return table; } @@ -71,4 +76,12 @@ public class TableConfig { public void setCreateTimeColumn(String createTimeColumn) { this.createTimeColumn = createTimeColumn.toLowerCase(); } + + public String getUpdateTimeColumn() { + return updateTimeColumn; + } + + public void setUpdateTimeColumn(String updateTimeColumn) { + this.updateTimeColumn = updateTimeColumn; + } } \ No newline at end of file diff --git a/src/main/java/com/yanghuanglin/seq/dao/SequencesUnlockDao.java b/src/main/java/com/yanghuanglin/seq/dao/SequencesUnlockDao.java index c9ab8bd..49baebc 100644 --- a/src/main/java/com/yanghuanglin/seq/dao/SequencesUnlockDao.java +++ b/src/main/java/com/yanghuanglin/seq/dao/SequencesUnlockDao.java @@ -10,6 +10,11 @@ import java.util.List; * @since 2022/1/28 */ public interface SequencesUnlockDao { + /** + * 查找某个未被锁定的序号 + */ + SequencesUnlock find(SequencesUnlock sequencesUnlock); + /** * 保存使用中的序号 */ diff --git a/src/main/java/com/yanghuanglin/seq/dao/SequencesUnusedDao.java b/src/main/java/com/yanghuanglin/seq/dao/SequencesUnusedDao.java index d44dc56..af1eb23 100644 --- a/src/main/java/com/yanghuanglin/seq/dao/SequencesUnusedDao.java +++ b/src/main/java/com/yanghuanglin/seq/dao/SequencesUnusedDao.java @@ -11,6 +11,11 @@ import java.util.List; */ public interface SequencesUnusedDao { + /** + * 查找某个未被使用的序号 + */ + SequencesUnused find(SequencesUnused sequencesUnused); + /** * 根据key,type查找seq最小的空闲序号 */ diff --git a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesBase.java b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesBase.java index ab0890a..22f208c 100644 --- a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesBase.java +++ b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesBase.java @@ -49,6 +49,7 @@ public abstract class SequencesBase { sql = sql.replaceAll("`seq`", String.format("`%s`", tableConfig.getSeqColumn())); sql = sql.replaceAll("`create_time`", String.format("`%s`", tableConfig.getCreateTimeColumn())); break; + case Dameng: case PostgreSQL: case KingbaseES: sql = sql.replaceAll("\"sequences(_unused|_unlock)\"", String.format("%s$1", tableConfig.getTable())); @@ -72,11 +73,12 @@ public abstract class SequencesBase { * @param sqlString sql语句 * @return 处理后的语句 */ - protected String adapter(String sqlString) { + protected String dbAdapter(String sqlString) { switch (dbType) { case MySQL: break; case PostgreSQL: + case Dameng: case KingbaseES: sqlString = sqlString.replaceAll("`(.+?)`", "\"$1\""); break; diff --git a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesDaoImpl.java b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesDaoImpl.java index 5f5720e..c50d720 100644 --- a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesDaoImpl.java +++ b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesDaoImpl.java @@ -12,7 +12,7 @@ import org.springframework.jdbc.core.JdbcTemplate; * @author yanghuanglin * @since 2022/1/28 */ -@SuppressWarnings("SqlResolve") +@SuppressWarnings({"SqlResolve", "SqlSourceToSinkFlow"}) public class SequencesDaoImpl extends SequencesBase implements SequencesDao { public SequencesDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType dbType) { @@ -24,11 +24,12 @@ public class SequencesDaoImpl extends SequencesBase implements SequencesDao { String sql = "select * from `%s` where `%s`=? and `%s`=?"; sql = String.format(sql, tableConfig.getTable(), tableConfig.getKeyColumn(), tableConfig.getTypeColumn()); try { - return this.jdbcTemplate.queryForObject(adapter(sql), (rs, rowNum) -> { + return this.jdbcTemplate.queryForObject(dbAdapter(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())); + result.setUpdateTime(rs.getDate(tableConfig.getUpdateTimeColumn())); return result; }, sequences.getKey(), sequences.getType()); } catch (EmptyResultDataAccessException ignored) { @@ -40,7 +41,7 @@ public class SequencesDaoImpl extends SequencesBase implements SequencesDao { 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(adapter(sql), sequences.getKey(), sequences.getType(), sequences.getSeq()); + int result = this.jdbcTemplate.update(dbAdapter(sql), sequences.getKey(), sequences.getType(), sequences.getSeq()); return result != 0; } @@ -48,7 +49,7 @@ public class SequencesDaoImpl extends SequencesBase implements SequencesDao { 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(adapter(sql), sequences.getSeq(), sequences.getKey(), sequences.getType()); + int result = this.jdbcTemplate.update(dbAdapter(sql), sequences.getSeq(), sequences.getKey(), sequences.getType()); return result != 0; } diff --git a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnlockDaoImpl.java b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnlockDaoImpl.java index 2cde9ee..bed5255 100644 --- a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnlockDaoImpl.java +++ b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnlockDaoImpl.java @@ -4,6 +4,7 @@ import com.yanghuanglin.seq.config.TableConfig; import com.yanghuanglin.seq.dao.SequencesUnlockDao; import com.yanghuanglin.seq.enums.DbType; import com.yanghuanglin.seq.po.SequencesUnlock; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; @@ -14,18 +15,36 @@ import java.util.List; * @author yanghuanglin * @since 2022/1/28 */ -@SuppressWarnings("SqlResolve") +@SuppressWarnings({"SqlResolve", "SqlSourceToSinkFlow"}) public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUnlockDao { public SequencesUnlockDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType 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 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(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; } @@ -36,9 +55,9 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn if (sequencesUnlock.getSeq() != null) { sql += " and `%s`=?"; 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 { - 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 listAll() { String sql = "select * from `%s_unlock`"; sql = String.format(sql, tableConfig.getTable()); - return this.jdbcTemplate.query(adapter(sql), rowMapper()); + return this.jdbcTemplate.query(dbAdapter(sql), rowMapper()); } @Override @@ -55,15 +74,15 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn if (begin != null && end != null) { sql = "select * from `%s_unlock` where `%s`>=? and `%s`<=?"; 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) { sql = "select * from `%s_unlock` where `%s`>=?"; 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) { sql = "select * from `%s_unlock` where `%s`<=?"; 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 { return listAll(); } @@ -73,7 +92,7 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn public boolean deleteAll() { String sql = "delete from `%s_unlock`"; sql = String.format(sql, tableConfig.getTable()); - int result = this.jdbcTemplate.update(adapter(sql)); + int result = this.jdbcTemplate.update(dbAdapter(sql)); return result != 0; } @@ -83,15 +102,15 @@ public class SequencesUnlockDaoImpl extends SequencesBase implements SequencesUn if (begin != null && end != null) { sql = "delete from `%s_unlock` where `%s`>=? and `%s`<=?"; 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) { sql = "delete from `%s_unlock` where `%s`>=?"; 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) { sql = "delete from `%s_unlock` where `%s`<=?"; 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 { return deleteAll(); } diff --git a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnusedDaoImpl.java b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnusedDaoImpl.java index 582e5cd..322b27f 100644 --- a/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnusedDaoImpl.java +++ b/src/main/java/com/yanghuanglin/seq/dao/impl/SequencesUnusedDaoImpl.java @@ -19,19 +19,37 @@ import java.util.List; * @author yanghuanglin * @since 2022/1/28 */ -@SuppressWarnings("SqlResolve") +@SuppressWarnings({"SqlResolve", "SqlSourceToSinkFlow"}) public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUnusedDao { public SequencesUnusedDaoImpl(JdbcTemplate jdbcTemplate, TableConfig tableConfig, DbType 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 public SequencesUnused findMinSeq(SequencesUnused sequencesUnused) { 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()); 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) { return null; } @@ -42,7 +60,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn try { 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()); - 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) { return null; } @@ -52,7 +70,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn public boolean delete(SequencesUnused sequencesUnused) { String sql = "delete from `%s_unused` where `%s`=? and `%s`=? and `%s`=?"; 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; } @@ -60,7 +78,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn public boolean save(SequencesUnused sequencesUnused) { 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()); - 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; } @@ -68,7 +86,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn public boolean saveBatch(List sequencesUnusedList) { 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()); - int[] result = this.jdbcTemplate.batchUpdate(adapter(sql), new BatchPreparedStatementSetter() { + int[] result = this.jdbcTemplate.batchUpdate(dbAdapter(sql), new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { SequencesUnused sequencesUnused = sequencesUnusedList.get(i); @@ -95,7 +113,7 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn public boolean deleteAll() { String sql = "delete from `%s_unused`"; sql = String.format(sql, tableConfig.getTable()); - int result = this.jdbcTemplate.update(adapter(sql)); + int result = this.jdbcTemplate.update(dbAdapter(sql)); return result != 0; } @@ -105,15 +123,15 @@ public class SequencesUnusedDaoImpl extends SequencesBase implements SequencesUn if (begin != null && end != null) { sql = "delete from `%s_unused` where `%s`>=? and `%s`<=?"; 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) { sql = "delete from `%s_unused` where `%s`>=?"; 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) { sql = "delete from `%s_unused` where `%s`<=?"; 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 { return deleteAll(); } diff --git a/src/main/java/com/yanghuanglin/seq/enums/DbType.java b/src/main/java/com/yanghuanglin/seq/enums/DbType.java index cbacebf..b512cfe 100644 --- a/src/main/java/com/yanghuanglin/seq/enums/DbType.java +++ b/src/main/java/com/yanghuanglin/seq/enums/DbType.java @@ -3,6 +3,8 @@ package com.yanghuanglin.seq.enums; public enum DbType { //MySQL数据库 MySQL("mysql"), + //达梦数据库 + Dameng("dm"), //人大金仓数据库 KingbaseES("pgsql"), //PostgreSQL数据库 diff --git a/src/main/java/com/yanghuanglin/seq/generator/Generator.java b/src/main/java/com/yanghuanglin/seq/generator/Generator.java index f4194ca..70e0638 100644 --- a/src/main/java/com/yanghuanglin/seq/generator/Generator.java +++ b/src/main/java/com/yanghuanglin/seq/generator/Generator.java @@ -221,6 +221,14 @@ public interface Generator { */ Sequences parse(String formatted, String pattern, Integer fixLength); + /** + * 查询序号是否已被锁定 + * + * @param sequences 需要查询的序号 + * @return 锁定结果 + */ + boolean locked(Sequences sequences); + /** * 锁定指定序号,在序号生成后,调用该序号的逻辑完成后需要执行此方法 *

@@ -244,6 +252,14 @@ public interface Generator { */ boolean lock(Sequences sequences, boolean ignoreSeq); + /** + * 将序号设为未使用 + * + * @param sequences 需要设为未使用的序号 + * @return 设置结果 + */ + boolean unused(Sequences sequences); + /** * 释放所有未使用的序号 *

diff --git a/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java b/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java index e76ae7a..c9a64ee 100644 --- a/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java +++ b/src/main/java/com/yanghuanglin/seq/generator/impl/SequencesGenerator.java @@ -22,6 +22,7 @@ import java.util.regex.Pattern; import static com.yanghuanglin.seq.enums.FormatPlaceholder.*; +@SuppressWarnings("CallToPrintStackTrace") public class SequencesGenerator implements Generator { private final TransactionTemplate transactionTemplate; private final SequencesDao sequencesDao; @@ -89,7 +90,11 @@ public class SequencesGenerator implements Generator { //根据传入的key和type新生成查询条件对象 Sequences condition = new Sequences(key, type); - if (!withOutSeq) { + if (Boolean.TRUE.equals(withOutSeq)) { + //不包含序号 + condition.setWithOutSeq(true); + return condition; + } else { //不是不包含序号的序号对象(有可能格式中只配置了#year##month##day#,序号就不用自增,也不用入库,直接返回即可) //找到正在使用的最大序号 Sequences sequences = sequencesDao.find(condition); @@ -123,9 +128,6 @@ public class SequencesGenerator implements Generator { } sequences.setWithOutSeq(false); return result ? sequences : null; - } else { - condition.setWithOutSeq(true); - return condition; } } catch (Exception e) { e.printStackTrace(); @@ -305,10 +307,30 @@ public class SequencesGenerator implements Generator { } @Override - public synchronized boolean lock(Sequences sequences) { - if (sequences == null || sequences.getWithOutSeq()) + public boolean locked(Sequences sequences) { + if (sequences == null || Boolean.TRUE.equals(sequences.getWithOutSeq())) return true; 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 -> { try { @@ -325,7 +347,7 @@ public class SequencesGenerator implements Generator { public synchronized boolean lock(Sequences sequences, boolean ignoreSeq) { if (!ignoreSeq) return lock(sequences); - if (sequences == null || sequences.getWithOutSeq()) + if (sequences == null || Boolean.TRUE.equals(sequences.getWithOutSeq())) return true; SequencesUnlock condition = new SequencesUnlock(sequences); 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 public synchronized boolean release() { //列出所有使用中表存在的序号 diff --git a/src/main/java/com/yanghuanglin/seq/po/Sequences.java b/src/main/java/com/yanghuanglin/seq/po/Sequences.java index 4ccd225..bdc114b 100644 --- a/src/main/java/com/yanghuanglin/seq/po/Sequences.java +++ b/src/main/java/com/yanghuanglin/seq/po/Sequences.java @@ -2,6 +2,8 @@ package com.yanghuanglin.seq.po; import com.yanghuanglin.seq.config.BaseConfig; +import java.util.Date; + /** * 当前序号 * @@ -24,6 +26,11 @@ public class Sequences { */ protected Long seq = 0L; + /** + * 最后使用时间 + */ + private Date updateTime; + /** * 临时字段,序号对应的年份(如2022年)(如果能获取到的话)。 * 该字段仅用于解析序号字符串时,解析出对应年份,用于合成key(如:序号对应的key为SNT+年份,返回的为其年份) @@ -101,6 +108,14 @@ public class Sequences { this.seq = seq; } + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + public Integer getYear() { return year; } @@ -180,10 +195,11 @@ public class Sequences { "key='" + key + '\'' + ", type='" + type + '\'' + ", seq=" + seq + + ", updateTime=" + updateTime + ", year=" + year + ", month=" + month + ", day=" + day + - ", fix=" + fix + + ", fix='" + fix + '\'' + ", withOutSeq=" + withOutSeq + '}'; } diff --git a/src/main/resources/dm/create_table_sequences.sql b/src/main/resources/dm/create_table_sequences.sql new file mode 100644 index 0000000..7f92767 --- /dev/null +++ b/src/main/resources/dm/create_table_sequences.sql @@ -0,0 +1,26 @@ +CREATE TABLE IF NOT EXISTS "sequences" +( + "key" VARCHAR(64) NOT NULL, + "type" VARCHAR(64) NOT NULL, + "seq" BIGINT NOT NULL, + "update_time" 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 '最后使用时间'; + +/* +@触发器设置,功能:自动记录更新时间 +@触发器名为 SEQUENCES_UPDATE_TIME +@触发器执行范围为每行生效 +*/ +CREATE OR REPLACE TRIGGER SEQUENCES_UPDATE_TIME BEFORE UPDATE ON "sequences" FOR EACH ROW +BEGIN + NEW."update_time":=SYSDATE; +END; + +/*启动触发器*/ +ALTER TRIGGER SEQUENCES_UPDATE_TIME ENABLE; \ No newline at end of file diff --git a/src/main/resources/dm/create_table_sequences_unlock.sql b/src/main/resources/dm/create_table_sequences_unlock.sql new file mode 100644 index 0000000..c766f58 --- /dev/null +++ b/src/main/resources/dm/create_table_sequences_unlock.sql @@ -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 '使用时间'; \ No newline at end of file diff --git a/src/main/resources/dm/create_table_sequences_unused.sql b/src/main/resources/dm/create_table_sequences_unused.sql new file mode 100644 index 0000000..a5ec720 --- /dev/null +++ b/src/main/resources/dm/create_table_sequences_unused.sql @@ -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 '设为闲置序号的时间'; \ No newline at end of file diff --git a/src/main/resources/mysql/create_table_sequences.sql b/src/main/resources/mysql/create_table_sequences.sql index aa2b45d..ff8c9a4 100644 --- a/src/main/resources/mysql/create_table_sequences.sql +++ b/src/main/resources/mysql/create_table_sequences.sql @@ -3,5 +3,6 @@ CREATE TABLE IF NOT EXISTS `sequences` `key` VARCHAR(64) NOT NULL COMMENT '序号英文名称', `type` VARCHAR(64) NOT NULL COMMENT '序号类型', `seq` BIGINT(20) NOT NULL COMMENT '已使用到的序号', + `update_time` DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '最后使用时间', PRIMARY KEY (`key`, `type`) ) COMMENT '当前序号表'; \ No newline at end of file diff --git a/src/main/resources/pgsql/create_table_sequences.sql b/src/main/resources/pgsql/create_table_sequences.sql index b964399..ffc36ef 100644 --- a/src/main/resources/pgsql/create_table_sequences.sql +++ b/src/main/resources/pgsql/create_table_sequences.sql @@ -1,11 +1,32 @@ CREATE TABLE IF NOT EXISTS "sequences" ( - "key" VARCHAR(64) NOT NULL, - "type" VARCHAR(64) NOT NULL, - "seq" INT8 NOT NULL, + "key" VARCHAR(64) NOT NULL, + "type" VARCHAR(64) NOT NULL, + "seq" INT8 NOT NULL, + "update_time" 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 '已使用到的序号'; \ No newline at end of file +COMMENT ON COLUMN "sequences"."seq" IS '已使用到的序号'; +COMMENT ON COLUMN "sequences"."update_time" IS '最后使用时间'; + + +/* +触发器函数,用户更新update_time字段 +*/ +CREATE OR REPLACE FUNCTION SEQUENCES_UPDATE_TIME() RETURNS TRIGGER AS $$ +BEGIN + NEW."update_time" := current_timestamp; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +/* +@触发器设置,功能:自动记录更新时间 +@触发器名为 SEQUENCES_UPDATE_TIME +@触发器执行范围为每行生效 +*/ +DROP TRIGGER IF EXISTS SEQUENCES_UPDATE_TIME ON "sequences" CASCADE; +CREATE TRIGGER SEQUENCES_UPDATE_TIME BEFORE UPDATE ON "sequences" FOR EACH ROW EXECUTE FUNCTION SEQUENCES_UPDATE_TIME(); \ No newline at end of file diff --git a/src/test/java/SeqTest.java b/src/test/java/SeqTest.java index 94496a5..29b4d1b 100644 --- a/src/test/java/SeqTest.java +++ b/src/test/java/SeqTest.java @@ -24,7 +24,7 @@ public class SeqTest { private static final Generator generator; static { - dataSource = pgsql(); + dataSource = mysql(); GeneratorConfig generatorConfig = new GeneratorConfig(dataSource); System.out.println("DbType: " + generatorConfig.getDbType()); @@ -124,4 +124,34 @@ public class SeqTest { sequences.setType("MISSION"); 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() { + 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); + } }