如何使用redis生成流水号

article/2025/11/8 16:34:02

概述
本文讲述如何使用redis生成流水号。本文是在Springboot中实现的。知道原理之后其他框架也可以轻松实现。
原理介绍
本文主要是使用redis的incr方法进行自增补零。然后结合时间、随机数、前缀组成唯一的流水号。
在这里插入图片描述
下面是流水号的结构。在这里插入图片描述
在文章的最后还是简单介绍一下redis的持久化。防止redis宕机导致自增数重置。从而导致流水号重复。

流程图

本次实现分为

1、初始化流水号信息进入缓存

2、生成流水号

下面是分别的大致流程图

1、初始化流水号信息进入缓存
在这里插入图片描述
2、生成流水号
在这里插入图片描述
代码实现
1、流水号实体类
用于存储流水号信息

@Data
public class YuSnGenCode {// 流水号生成依赖的类,会使用类的名称作为redis的key private Class entity;// 前缀private String prefix;// 自增数位数 自增数达不到此位数自动补零private Integer num;public YuSnGenCode(Class entity, String prefix, Integer num) {this.entity = entity;this.prefix = prefix;this.num = num;}
}

2、初始化流水号进入缓存
在程序启动之后初始化流水号

@Component
@Slf4j
public class YuSnGenStart implements ApplicationRunner {@AutowiredYuSnGenUtil yuSnGenUtil;@Overridepublic void run(ApplicationArguments args) throws Exception {log.info("=====开始初始化流水号=====");List<YuSnGenCode> yuSnGenCodeList = new ArrayList<>();yuSnGenCodeList.add(new YuSnGenCode(Account.class, "AC", 6));yuSnGenCodeList.add(new YuSnGenCode(Shop.class, "DP", 6));yuSnGenCodeList.add(new YuSnGenCode(Order.class, "OR", 6));yuSnGenCodeList.add(new YuSnGenCode(Dispatch.class, "DL", 6));yuSnGenCodeList.add(new YuSnGenCode(Refund.class, "RF", 6));yuSnGenCodeList.add(new YuSnGenCode(PayLog.class, "PL", 6));yuSnGenCodeList.add(new YuSnGenCode(Withdrawal.class, "WR", 6));yuSnGenCodeList.add(new YuSnGenCode(Aftermarket.class, "AS", 6));yuSnGenCodeList.add(new YuSnGenCode(Coupon.class, "CO", 6));yuSnGenCodeList.add(new YuSnGenCode(CouponGen.class, "CG", 10));yuSnGenCodeList.add(new YuSnGenCode(Draw.class, "DP", 6));yuSnGenUtil.init(yuSnGenCodeList);log.info("=====初始化流水号完毕=====");}
}
 public void init(List<YuSnGenCode> yuSnGenCodes) {// 流水号初始化入缓存for (YuSnGenCode yuSnGenCode : yuSnGenCodes) {String redisKey = yuSnGenCode.getEntity().getName();// 存入缓存 key:key:实体类名称 value:流水号数据(前缀、自增数位数)redisTemplate.opsForValue().set(yuSnGenCode.getEntity().getName(), FastJsonUtils.toJsonStr(yuSnGenCode));log.info(yuSnGenCode.getEntity().getName() + "已初始化");}}

初始化之后的流水号如下图所示

在这里插入图片描述
3、生成流水号

 public Optional<String> gen(Class c) {// 获取实体类的名称String redisKey = c.getName();// 判断是不是有初始化此实体类if (null != redisTemplate.opsForValue().get(redisKey)) {// 从缓存获取流水号的生成信息YuSnGenCode yuSnGenCode = FastJsonUtils.toBean(redisTemplate.opsForValue().get(redisKey).toString(), YuSnGenCode.class);// 根据流水号的前缀判断今天是否有生成过流水号if (redisTemplate.opsForValue().get(yuSnGenCode.getPrefix()) == null) {// 没有则新建一个存入缓存 格式(key:OR  value:0)// 设置到第二天早上00:00:01过期Long todayTime = LocalDate.now().plusDays(1).atTime(0, 0, 0, 1).atOffset(ZoneOffset.ofHours(8)).toEpochSecond();Long nowTime = LocalDateTime.now().atOffset(ZoneOffset.ofHours(8)).toEpochSecond();Long expireTime = todayTime - nowTime;redisTemplate.opsForValue().set(yuSnGenCode.getPrefix(), 0, expireTime*1000, TimeUnit.MILLISECONDS);}// 进行自增操作StringBuffer sn = new StringBuffer();// 和前缀、时间、随机数进行组合sn.append(yuSnGenCode.getPrefix());String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));sn.append(date);Long num = redisTemplate.opsForValue().increment(yuSnGenCode.getPrefix());sn.append(addZero(String.valueOf(num), yuSnGenCode.getNum()));String random = String.valueOf(new Random().nextInt(1000));sn.append(random);// 生成最终的流水号返回return Optional.ofNullable(sn.toString());}return Optional.ofNullable(null);}
 // 自动补零public String addZero(String numStr, Integer maxNum) {int addNum = maxNum - numStr.length();StringBuffer rStr = new StringBuffer();for (int i = 0; i < addNum; i++) {rStr.append("0");}rStr.append(numStr);return rStr.toString();}

第一次生成流水号之后redis中会有一个以此流水号的前缀作为key的数据,后续直接进行自增。无需新增

在这里插入图片描述
代码测试
普通测试

   public Response test2() {return Response.success(yuSnGenUtil.gen(Order.class).get());}

结果如下
在这里插入图片描述
并发测试
这里我们使用ab进行压力并发测试

测试前我们流水号数据为0
在这里插入图片描述
进行5000请求100并发的测试
在这里插入图片描述
请求完毕之后流水号的数据是5000是没有问题的。
在这里插入图片描述
redis 持久化
redis持久化指redis意外退出之后重启仍然能够恢复之前数据。我们这里使用redis持久化防止redis意外退出重启导致流水号数据重置,从而导致我们的流水号生成重复。

Redis 提供了不同级别的持久化方式:

RDB

RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.

AOF

AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据

我们本次使用的是AOF的方式
在这里插入图片描述
根据官网的提示。我们只需要去redis.config文件中开启appendonly就可以了。这样redis会生成appendonly.aof文件,服务器重启的时候会重新执行这些命令来恢复原始的数据。
在这里插入图片描述
注意
因为AOF的默认备份方式有三种
1、always每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全

2、everysec每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。

3、no从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。

而我们采用的是第二种。也是AOF默认的的。但是这样故障时可能会损失1s的数据,所以如果对数据要求十分严格的同学可以采用第一种方式只需要修改redis.config文件的appendfsync属性即可
在这里插入图片描述
本文转载于->布丁萨玛


http://chatgpt.dhexx.cn/article/tZNjbgSX.shtml

相关文章

谈谈订单号和流水号的关系

订单号和流水号是不同的。 首先订单号是订单唯一的编号&#xff0c;而且电商平台的各种子系统也是根据订单来统计业务完成的情况&#xff0c;订单编号经常用来被查询&#xff0c;所以数据类型必须是数字&#xff0c;而且是全局唯一&#xff0c;那肯定就得主键字段了。 然后流水…

低代码学习教程:生成固定格式流水号

方法1&#xff1a;RECNO()方法2&#xff1a;MAPX() 表单设计中经常涉及流水号的制作问题&#xff0c;下面就分别介绍下两种编号的实现方法&#xff0c;大家可以根据需要自行选择。 注意&#xff1a; 百数已支持【流水号】控件&#xff0c;如有特殊要求可参考文档&#xff1a;…

【26天高效学习Java编程】Day19:Java 多线程

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;由浅入深讲解Java的基本使用&#xff0c;希望大家都能够从中有所收获&#xff0c;也请大家多多支持。 专栏地址:26天高效学习Java编程 相关软件地址:软件地址 所有代码地址:代码地址 如果文章知识点有错误的地方&#x…

怎么入门学习Java编程

因为目前java非常火,应用非常的广泛,是目前最火的行业之一,竞争很大,工资很高,未来发展也极好。 如条件还可以,负担不是那么大,可以选择培训,培训一定会比你自学的好,如果培训都学不好,自学肯定更难。目前java的培训费用都是2W+,这还只是培训费而已,加上一些其他的…

Java学习

集合 什么是集合&#xff1f; 集合&#xff1a;集合是java中提供的一种容器&#xff0c;可以用来存储多个数据。 集合和数组的区别 数组的长度是固定的。集合的长度是可变的。 数组中存储的是同一类型的元素&#xff0c;可以存储任意类型数据。集合存储的都是引用数据类型。如…

想学习Java编程,看书还是看视频更合适?

首先&#xff1a;自己本身就是初级或者零基础的&#xff0c;自己对软件了解的都不足够&#xff0c;跟着视频学&#xff0c;老师操作操作一步你就能看着他操作&#xff0c;这样心里更有谱。 第二&#xff1a;跟着视频学能学的更好&#xff0c;知识体系更全&#xff0c;一般视频…

自学过来人告诉你,初学者应该怎么快速的学习Java编程?

我说说我个人的案例吧&#xff0c;我电子信息专业&#xff0c;后来选择做了Java开发&#xff0c;在11年的时候开始学习的Java&#xff0c;可以说那时候的企业要求低于现在&#xff0c;我当时学习由于没有钱&#xff0c;我是自学的&#xff0c;我大学学过C语言 我晚上下班的时候…

通过项目驱动的学习方法快速掌握Java编程

摘要 Java作为一种广泛应用于软件开发领域的编程语言&#xff0c;对于零基础的学习者来说&#xff0c;学习Java编程可能存在一定的难度。本文将介绍如何通过项目驱动的学习方法&#xff0c;帮助零起点的学习者快速掌握Java编程。通过以项目为核心的学习路径、结合实践和理论的…

Java学习之编程入门

0 编程入门 0.1 概述0.2 计算机硬件介绍0.2.1 中央处理器0.2.2 存储设备0.2.3 内存0.2.4 输入和输出设备0.2.5 通信设备 0.3 计算机发展史上的鼻祖0.4 操作系统0.5 万维网0.6 职业发展与提升0.7 学习经验探讨 0.1 概述 计算机包括硬件(hardware)和软件(software)两部分。 硬件…

学习Java编程知识 必知要点

Java 是全球最受欢迎的编程语言之一&#xff0c;在世界编程语言排行榜 TIOBE 中&#xff0c;Java 一直霸占着前三名&#xff0c;有好多年甚至都是第一名。那么如此强大的Java你真的了解他的知识体系吗&#xff1f;他的学习路线你知道吗&#xff1f; 1. Java虚拟机——JVM JVM&a…

java三大平台介绍,选择哪个平台学习java编程?

&#x1f482; 个人主页: IT学习日记&#x1f91f; 版权: 本文由【IT学习日记】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦&#x1f485; 想寻找共同成长的小伙伴&#xff0c;请点击【技术圈子】 眼见…

学习java

Java 深度历险(作者成富&#xff0c;是IBM 中国软件开发中心的高级工程师) 2 目录 序 .................................................................................................................................. 1 目录 ................................…

Java怎么学习

入门的时候一定要搞清楚面向对象相关的概念 对象&#xff0c;类&#xff0c;实例&#xff0c;这三者的含义&#xff0c;还有三者之间有什么关系。 类之间的关系有那些<继承&#xff0c;聚合 组合&#xff0c;普通关联 自返关联>&#xff0c;关联的多重性&#xff0c;都…

Java:学习Java编程的主要技巧

随着互联网时代的发展&#xff0c;软件开发行业热度不断飙升&#xff0c;企业对软件开发人才需求量也与日俱增&#xff0c;尤以Java工程师为首&#xff0c;这也是一直以来Java培训日趋火热的原因。那么今天小编就和大家说说学Java编程的几个学习技巧 你精通基础知识吗? 掌握基…

JAVA编程入门学习

JAVA编程入门学习 本次学习内容&#xff1a; 1、Java初步讲解 2、Java运行环境的安装及应用 3、进行简单的Java编程 一、程序&#xff1a; 程序 算法 数据结构 用户使用编程语言实现问题域到解域的映射&#xff0c;细节描述算法。 1、编程语言——三大类&#xff1a;…

Java编程入门

Java编程入门 初始Java开发Java编程起步JShell工具CLASSPATH 环境属性 JAVA基本概念注释标志符与关键字 JAVA数据类型划分JAVA数据类型简介整型数据类型浮点型数据字符型数据布尔数据String 字符串 Java运算符运算符简介数学运算符关系运算符逻辑运算符位运算 Java程序逻辑控制…

JAVA基础入门学习编程

第一章 使用记事本编写一个HelloWorld程序&#xff0c;并在命令行窗口编译运行&#xff0c;并打印输出结果。 public class HelloWorld {public static void main(String[] args) {System.out.println("Hello World!!");} } 第二章 1、请编写程序&#xff0c;实…

学习Java编程入门书籍

《Head First Java》 《Head First Java》被亚马逊评为十大好书之一。在京东计算机类书籍中热度排名第16位&#xff0c;在Java类书籍中排名第2位。豆瓣评分为8.8分&#xff0c;有百分之54.4%的读者给出了五星评价。在知乎社区中有来自无数位的大神做推荐。哪本书适合推荐给 Ja…

初学者怎么学习java编程

1。java是分为三个主要方向&#xff1a; CS架构&#xff08;java SE&#xff09;。BS架构&#xff08;java web&#xff09;。java手机开发&#xff08;java ME&#xff09;&#xff0c;非Android开发。 &#xff08;1&#xff09;、java CS架构&#xff08;客户端/服务器&am…

Java 学习(一)Java语言基础

Java 语言基础&#xff08;一&#xff09; 前言一、注释和标识符1. 注释2. 字符集3. 标识符4. 关键字(略) 二、数据类型1.基本类型2.引用类型 三、 常量和变量1.常量2.变量 四、操作符1.赋值运算符2.算术运算符3.关系运算符4.逻辑运算符5.位运算符6.三位运算符7.instanceof运算…