基于mysql的单据号生成(前缀+日期+自增id+后缀)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了基于mysql的单据号生成(前缀+日期+自增id+后缀),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5851字,纯文字阅读大概需要9分钟。
内容图文
![基于mysql的单据号生成(前缀+日期+自增id+后缀)](/upload/InfoBanner/zyjiaocheng/879/5dad275ab9ea45a28605df72a637706a.jpg)
介绍
本次采用mysql处理,性能不是很好,对于高并发有要求的建议不要采用
公司一个小项目,需要生成一个单据号,格式为: 日期 + 每日重新自增号,自己考虑了一下每日自增需要考虑并发和持久问题,两种数据库redis和mysql由于项目较小,所以没有redis因为这个增加一个redis好像有点不值得,所以采用mysql作为持久化处理,一下思路也是借鉴了网上的许多想法
源码
源码查看规则
源码位置: blog-study:module-utils:work-no
欢迎大家随时批评指正
思路
- 首先根据需求,需要这样一个格式: 20200101 + 00001 的单据号
- 分析日期只需要获取当前时间格式化即可简单,
自增号:
1)需要考虑每日重新开始
2)宕机数据可以持久化(存库即可)
3)并发获取单据号唯一
以上四个问题只需要考虑 每日重新开始计数和并发问题 - 每日重新开始,在数据库中加一个时间标志,每次获取都与当前时间做对比然后做相应处理, 并发问题我能想到的就是加锁(编程锁或者数据库锁,我这里采用lock锁)
- 以上基本可以解决项目问题了,然后思考是否可以用于其它业务号的生成
1)于是想可以增加业务标识、前缀和后缀来满足不同业务,其中业务标识不参与单据号组成只是标识某一类单据号,这样可以保证不同业务可以使用相同的单据号,前缀是根据业务需要标识业务单据号的参与单据号生成, 后缀的作用是干扰随机数,可以尽可能防止他人直接看出来业务单据每日的生成数量
格式: GX + 20200101 + 00001 + 23
2) 每日重新开始计数,是否可以改为可选择的,每月重新计数,每年重新计数,或者一直不需要重新计数 - 思考是否可以封装为组件,引入依赖直接就可以使用,想了一下自己目前还不具备这种能力吧,以后还要多学多了解,也希望大家可以多多指点,小子将不胜感激。
功能介绍
- 数据库结构(使用实体类代替)
/**
?????*?业务唯一标识(只是作为唯一标识,并不参与单据号的生成)
?????*/
????private?String?workNo;
????/**
?????*?业务码前缀
?????*/
????private?String?prefix;
????/**
?????*?序号
?????*/
????private?Integer?serialNum;
????/**
?????*?序号长度
?????*/
????private?Integer?serialLength;
????/**
?????*?序号之后的随机数长度(干扰串)
?????*/
????private?Integer?randomLength;
????/**
?????*?重置模式(0:无需重置,1:?按天重置,?2:?按月重置,?3:?按年重置)
?????*/
????private?Integer?restType;
????/**
?????*?重置时间(检测是否需要重置使用)
?????*/
????private?LocalDate?restTime;
????/**
?????*?创建时间
?????*/
????private?LocalDateTime?createTime;
????/**
?????*?修改时间
?????*/
????private?LocalDateTime?updateTime;
????/**
?????*?备注
?????*/
????private?String?remark;
- 业务号格式使用枚举规定好,每次启动项目自动识别处理
/**
?????*?为了保证每次生成的单号一致性,所以初始化作为第一次初始化成功后不再修改
?????*/
????ORDER_NO("XG",?"XG",?5,?2,?1,?"小郭测试单据号");
????/**
?????*?业务唯一标识(只是作为唯一标识,并不参与单据号的生成)
?????*/
????private?String?workNo;
????/**
?????*?业务码前缀
?????*/
????private?String?prefix;
????/**
?????*?序号长度
?????*/
????private?Integer?serialLength;
????/**
?????*?序号之后的随机数长度(干扰串)0代表没有干扰
?????*/
????private?Integer?randomLength;
????/**
?????*?重置模式(0:无需重置,1:?按天重置,?2:?按月重置,?3:?按年重置)
?????*/
????private?Integer?restType;
????/**
?????*?备注
?????*/
????private?String?remark;
项目启动初始化:
@Configuration
public?class?WorkNoInit?implements?ApplicationRunner?{
????@Autowired
????private?WorkNoDao?workNoDao;
????/**
?????*?单据号初始化
?????*
?????*?@param?args
?????*?@throws?Exception
?????*/
????@Override
????public?void?run(ApplicationArguments?args)?throws?Exception?{
????????WorkNoInfo?workNoInfo?=?null;
????????for?(WorkInfoEnum?workInfoEnum?:?WorkInfoEnum.values())?{
????????????workNoInfo?=?new?WorkNoInfo(workInfoEnum);
????????????//查询是否已有该业务单据号(没有初始化)
????????????if?(workNoDao.isHaveWorkNo(workNoInfo.getWorkNo())?==?0)?{
????????????????workNoDao.addOrderNumInfo(workNoInfo);
????????????}
????????}
????}
}
- 获取单据号:
@Component
public?class?WorkNoService?{
????@Autowired
????private?WorkNoDao?workNoDao;
????private?static?Lock?lock?=?new?ReentrantLock();
????/**
?????*?获取业务序列码
?????*
?????*?流程:
?????*?1.?加锁保证线程安全
?????*?2.?查询数据库中的业务信息
?????*?3.?判断重置模式修改数据库中相应的数据
?????*?4.?返回业务码
?????*
?????*?@param?workInfoEnum?枚举
?????*?@return?业务序列码
?????*/
????public?String?getOrderNo(WorkInfoEnum?workInfoEnum)?{
????????lock.lock();
????????LocalDateTime?localDateTime?=?LocalDateTime.now();
????????try?{
????????????WorkNoInfo?workNoInfo?=?workNoDao.queryByWorkNo(workInfoEnum.getWorkNo());
????????????if?(workNoInfo?==?null)?{
????????????????throw?new?ErrorCodeException(500,?"查询生成业务码基础数据失败!");
????????????}
????????????//序号
????????????Integer?serialNum?=?workNoInfo.getSerialNum();
????????????//判断是否需要重置序号
????????????if?(workNoInfo.getRestType()?==?1)?{
????????????????String?dayTime?=?localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
????????????????String?dataBaseTime?=?workNoInfo.getRestTime().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
????????????????if?(!dataBaseTime.equals(dayTime))?{
????????????????????serialNum?=?0;
????????????????}
????????????}?else?if?(workNoInfo.getRestType()?==?2)?{
????????????????String?monthTime?=?localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
????????????????String?dataBaseTime?=?workNoInfo.getRestTime().format(DateTimeFormatter.ofPattern("yyyyMM"));
????????????????if?(!dataBaseTime.equals(monthTime))?{
????????????????????serialNum?=?0;
????????????????}
????????????}?else?if?(workNoInfo.getRestType()?==?3)?{
????????????????String?yearTime?=?localDateTime.format(DateTimeFormatter.ofPattern("yyyy"));
????????????????String?dataBaseTime?=?workNoInfo.getRestTime().format(DateTimeFormatter.ofPattern("yyyy"));
????????????????if?(!dataBaseTime.equals(yearTime))?{
????????????????????serialNum?=?0;
????????????????}
????????????}
????????????workNoInfo.setSerialNum(serialNum?+?1);
????????????workNoInfo.setRestTime(localDateTime.toLocalDate());
????????????//更新数据库
????????????workNoDao.updateOrderNo(workNoInfo);
????????????return?workNoInfo.getNo();
????????}?catch?(Exception?e)?{
???????????throw?new?ErrorCodeException(500,?"生成业务码失败"?+?e.getMessage());
????????}?finally?{
????????????lock.unlock();
????????}
????}
}
内容总结
以上是互联网集市为您收集整理的基于mysql的单据号生成(前缀+日期+自增id+后缀)全部内容,希望文章能够帮你解决基于mysql的单据号生成(前缀+日期+自增id+后缀)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。