java 数据路id增长策略_基于数据库实现ID自动生成策略
实现类似mysql的主键递增功能, 并在此基础上做了增强, 可对于不同分类, 不同主键前缀自动递增。
表结构设计
t_sequence
字段
描述
ID
数据库主键
SEQ_PREFIX
生成的主键前缀
SEQ_TYPE
生成的主键类型
SEQ_NUM
生成的主键的最新序号
SEQ_GEN_DATE
主键最新更新时间
SEQ_CATEGORY
主键分类
SEQ_CHAR_WIDTH
主键数字部分的最大宽度, 如果seq_num的位数小于这个宽度, 则最终生成的主键前面补0
上代码:SequenceGenerator.java
public final class SequenceGenerator {
private static final Log logger = LogFactory.getLog(SequenceGenerator.class);
private static final String DEFAULT_SEQ_CATEGORY = "common";
private static final Integer DEFAULT_SEQ_CHAR_WIDTH=4;
private static final String SEQ_TYPE_NUMERIC="INT";
private static final String SEQ_TYPE_CHAR="VARCHAR2";
private final ReentrantLock lock = new ReentrantLock();
private static class SequenceGeneratorHolder{
private static SequenceGenerator instance = new SequenceGenerator();
}
private SequenceGenerator(){}
public static SequenceGenerator getInstance(){
return SequenceGeneratorHolder.instance;
}
public Integer getId(SequenceModel seqCriteria){
final ReentrantLock lock = this.lock;
lock.lock();
try{
SequenceService sequenceService = ApplicationContextProvider.getBean(SequenceService.class);
return sequenceService.getSeqId(seqCriteria); //查询数据库在最新的Seq_num基础上加1
}finally {
lock.unlock();
}
}
/**
* 默认生成不带前缀的字符串id
*
* @return
*/
public String generateStringId(){
return generateStringId(DEFAULT_SEQ_CATEGORY,DEFAULT_SEQ_CHAR_WIDTH);
}
/**
* 根据类别生成字符串ID, 使用默认字符宽度为4, 并且带前缀和category 一致
* @param category
* @return
*/
public String generateStringId(String category){
return generateStringId(category,category,DEFAULT_SEQ_CHAR_WIDTH);
}
public String generateStringId(String prefix,String category){
return generateStringId(prefix,category,DEFAULT_SEQ_CHAR_WIDTH);
}
/**
* generate varchar type id without prefix
* @param category
* @return
*/
public String generateStringId(String category, Integer charWidth){
return generateStringId(null,category,charWidth);
}
/**
*
* @param prefix
* @param category
* @param charWidth
* @return
*/
public String generateStringId(String prefix,String category, Integer charWidth){
SequenceModel seqCriteria = new SequenceModel();
seqCriteria.setSeqCategory(category);
seqCriteria.setSeqPrefix(prefix);
seqCriteria.setSeqCharWidth(charWidth);
seqCriteria.setSeqType(SEQ_TYPE_CHAR);
Integer result = getId(seqCriteria);
String numStr = StrUtil.padPre(String.valueOf(result),charWidth,'0');
String id = StrUtil.nullToEmpty(prefix)+numStr;
return id;
}
public Integer generateNumericId(){
return generateNumericId(DEFAULT_SEQ_CATEGORY);
}
/**
* generate long type id
* @return
*/
public Integer generateNumericId(String category){
SequenceModel seqCriteria = new SequenceModel();
seqCriteria.setSeqCategory(category);
seqCriteria.setSeqType(SEQ_TYPE_NUMERIC);
Integer result = getId(seqCriteria);
return result;
}
}
SequenceModel.java ---表结构对象封装
@Data
public class SequenceModel {
private Integer id;
private String seqPrefix;
private String seqType;
private Integer seqNum;
private String seqCategory;
private Integer seqCharWidth;
private Date seqGenDate;
}
SequenceService.java
这里才是整个生成策略的核心, 查询数据库的时候需要加悲观锁, 锁住整行数据, 查询,插入, 更新需要在同一个事务内完成, 否则容易发生死锁。
使用Mybatis操作数据库
@Service
public class SequenceService {
@Autowired
private SequenceMapper sequenceMapper;
@Transactional(transactionManager = "businessDataSourceTM") // 这行不能少
public Integer getSeqId(SequenceModel seqCriteria){
try {
SequenceModel seqResult = sequenceMapper.findSequence(seqCriteria);
AtomicInteger atomicInteger = new AtomicInteger();
if(seqResult == null){
// 新建
seqResult = seqCriteria;
seqResult.setSeqNum(atomicInteger.incrementAndGet());
seqResult.setSeqGenDate(DateUtil.nowDate());
sequenceMapper.insertSequenceNum(seqResult);
}else{
//更新
Integer seqNum = seqResult.getSeqNum();
atomicInteger.set(seqNum);
seqResult.setSeqNum(atomicInteger.incrementAndGet());
seqResult.setSeqGenDate(DateUtil.nowDate());
sequenceMapper.updateSequenceNum(seqResult);
}
return atomicInteger.get();
} catch (Exception e) {
log.error("generate Id occurs error.",e);
return 0;
}
}
}
sequence-generator.xml -- mybatis SQL配置文件
select
seq.ID,
seq.SEQ_PREFIX,
seq.SEQ_TYPE,
seq.SEQ_NUM,
seq.SEQ_CHAR_WIDTH,
seq.SEQ_GEN_DATE,
seq.SEQ_CATEGORY
from t_sequence seq
where 1=1
and seq.SEQ_CATEGORY = #{seqCriteria.seqCategory}
and seq.SEQ_PREFIX = #{seqCriteria.seqPrefix}
for update
update t_sequence set seq_num=#{seq.seqNum}, seq_gen_date=#{seq.seqGenDate,jdbcType=TIMESTAMP} where id=#{seq.id}
SELECT CZBANK_COMMON_SEQ.NEXTVAL as ID from DUAL
insert into t_sequence (
id,
SEQ_PREFIX,
SEQ_TYPE,
SEQ_NUM,
SEQ_CHAR_WIDTH,
SEQ_GEN_DATE,
SEQ_CATEGORY
) VALUES (
#{id},
#{seq.seqPrefix,jdbcType=VARCHAR},
#{seq.seqType,jdbcType=VARCHAR},
#{seq.seqNum},
#{seq.seqCharWidth,jdbcType=INTEGER},
#{seq.seqGenDate},
#{seq.seqCategory}
)
SequenceMapper.java
@Mapper
public interface SequenceMapper {
SequenceModel findSequence(@Param("seqCriteria") SequenceModel seqCriteria);
void updateSequenceNum(@Param("seq") SequenceModel seq);
void insertSequenceNum(@Param("seq") SequenceModel seq);
}
java 数据路id增长策略_基于数据库实现ID自动生成策略相关推荐
- 用java写ods系统_基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(TableGo v7.0.0版)...
TableGo是基于数据库的代码自动生成工具,低代码编程技术的实现,可以零代码自动生成SpringBoot项目工程.生成JavaBean.生成前后端分离的CRUD代码.生成MyBaits的Mapper ...
- java生成iso9660工具_基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(TableGo v7.0.0版)...
TableGo_20210212 v7.0.0 正式版发布,此次版本更新如下: 1.新增对DB2数据库的支持 2.新增按字段生成文件,支持把字段.JSON.XML数据转换成任何代码 3.新增大量新的自 ...
- mysql javabean 工具_基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.9.0版)...
TableGo_20200520 v6.9.0 正式版发布,此次版本更新如下: 1.新增对JDK9及以上版本Java环境的支持 2.生成JavaBean更名为生成数据模型并且提供了C#.C++.Gol ...
- freemarker mysql 生成bean_基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.6.6版)...
TableGo_20191026 v6.6.6 正式发布,此次版本更新如下: 1.新增通过自定义模板生成Word文档的功能,可以使用FreeMarker模板生成自定义格式的数据库文档. 2.新增 Sw ...
- 基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.9.0版)
TableGo_20200520 v6.9.0 正式版发布,此次版本更新如下: 1.新增对JDK9及以上版本Java环境的支持 2.生成JavaBean更名为生 ...
- 基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(TableGo v7.4.0版)
TableGo_20210921 v7.4.0 正式版发布,此次版本累计更新如下: 1.新增企业或个人的简单定制版本,为企业和个人提供软实力的增值 2.新增导入 ...
- mysql 分库分表策略_【数据库】分库分表策略
关系型数据库本身比较容易成为系统瓶颈,单机存储容量.连接数.处理能力都有限.当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库.优化索引,做很多操作时性能仍下降严重.此时就要考 ...
- python股票策略_基于python的股票自动盯盘程序
不是每个人都有时间时刻盯盘的,而且股票那么多,往往挂一漏万,错过很多好的股票和买入机会.笔者尝试用python实现了一个可以自动盯盘的程序,调用了一个免费的股票数据接口baostock提供的历史行情数 ...
- 用java做小学数学系统_小学生数学练习题目自动生成系统——java课程设计
<小学生数学练习题目自动生成系统--java课程设计>由会员分享,可在线阅读,更多相关<小学生数学练习题目自动生成系统--java课程设计(37页珍藏版)>请在金锄头文库上搜索 ...
最新文章
- jsp与java_JSP与JavaBeans
- XCode真机测试发布时产生The executable was signed with invalid entitlements.解决办法
- MBE:ggtreeExtra-用图层叠加方法绘制环形进化树
- 真正理解线程上下文类加载器(多案例分析)
- Vertica 高可用性测试
- 多层mvc,thikphp进阶
- 数据库连接类:DatabaseConnection
- 智能城市dqn算法交通信号灯调度_博客 | 滴滴 KDD 2018 论文详解:基于强化学习技术的智能派单模型...
- 爬虫 动态生成useragent的功能 fake-useragent库
- maven报错:Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:x.x.x:test
- 大数据发展历程及技术选型
- Vue三大核心概念之二(事件)
- 屏蔽键盘信息(低级键盘钩子)
- 外星人 Alienware X14 评测
- Mac 安装IE浏览器
- Conflicted Confucians
- Linux perf 1.4、hardware events
- 曾经觉得学习晦涩难懂的我是如何爱上linux
- 集成显卡 独立显卡 CPU核心显卡的区别
- Windows Server域控制器更改IP步骤
热门文章
- 面向项目(二)—— visual studio 的使用
- Tricks(三十八)—— 在不计算欧式距离的前提下判断点到两点的距离哪个更近
- C基础——fopen() 的 mode参数
- 一行代码进行闰年的判断
- python列表删除行_Python DataFrame – 删除具有属于值列表的列值的行
- vue树形权限菜单_Vue.js 递归组件实现树形菜单
- python编程入门-Python 异步编程入门
- 0基础学python要多久-零基础python培训需要学多久?
- python教程-Python入门教程完整版(懂中文就能学会)
- 自学python好找工作么-学习python后好找工作吗