使用redis RedisAtomicLong 生成订单号

背景

产品需求要生成有序的订单 key+ 年月日时分秒 +6位序号 由00001-99999组成 且每天都是从00001开始

公司系统有部署多台服务,这需要一个有序的序列不能重复而且得保证获取时的原子性这里 我们考虑使用了redis Incr 这个命令

Redis Incr 命令能将 key 中储存的数字值增一,这样就不会取到重复的编号。

需要提前引入Redis

使用

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;public class DateUtils {public static final long ONE_DAY_MILLS = 3600000 * 24;private DateUtils() {}/*** 日期格式     enum(枚举类型):一组类似的值包含到一种类型当中。而这种枚举类型的名称则会被定义成独一无二的类型描述符 -->为申明的变量提供更大的取值范围*/public enum DateFormat {/*** 格式:"yyyyMMddHHmmss"*/ALLTIME {@Overridepublic String getValue() {return "yyyyMMddHHmmss";}},/*** 格式:"yyyy-MM-dd HH:mm:ss"*/ALL_TIME {public String getValue() {return "yyyy-MM-dd HH:mm:ss";}},/*** 格式:"yyyy-MM-dd HH:mm"*/ONLY_MINUTE {public String getValue() {return "yyyy-MM-dd HH:mm";}},/*** 格式:"yyyy-MM-dd HH"*/ONLY_HOUR {public String getValue() {return "yyyy-MM-dd HH";}},/*** 格式:"yyyy-MM-dd"*/ONLY_DAY {public String getValue() {return "yyyy-MM-dd";}},/*** 格式:"yyyy-MM"*/ONLY_MONTH {public String getValue() {return "yyyy-MM";}},/*** 格式:"MM-dd"*/ONLY_MONTH_DAY {public String getValue() {return "MM-dd";}},/*** 格式:"MM-dd HH:mm"*/ONLY_MONTH_SEC {public String getValue() {return "MM-dd HH:mm";}},/*** 格式:"HH:mm:ss"*/ONLY_TIME {public String getValue() {return "HH:mm:ss";}},/*** 格式:"HH:mm"*/ONLY_HOUR_MINUTE {public String getValue() {return "HH:mm";}};public abstract String getValue();}/*** 获取当前时间  格式---->2019-08-04    13:30:29*/public static String getNowTime(DateFormat format) {String nowtime = null;Calendar calendar = Calendar.getInstance();Date dateNow = calendar.getTime();SimpleDateFormat sdf = new SimpleDateFormat(format.getValue(), Locale.CHINA);nowtime = sdf.format(dateNow);return nowtime;}/*** 将一个日期字符串转换成Data对象         string-->date** @param dateString 日期字符串* @param format     转换格式* @return*/public static Date stringToDate(String dateString, DateFormat format) {Date date = null;SimpleDateFormat sdf = new SimpleDateFormat(format.getValue(), Locale.CHINA);try {date = sdf.parse(dateString);} catch (ParseException e) {e.printStackTrace();}return date;}/*** 将date转换成字符串               date--->string** @param date   日期* @param format 日期目标格式* @return*/public static String dateToString(Date date, DateFormat format) {String string = "";SimpleDateFormat sdf = new SimpleDateFormat(format.getValue(), Locale.CHINA);string = sdf.format(date);return string;}/*** 获取指定日期** @param date 指定日期* @return 返回值为: "周日", "周一", "周二", "周三", "周四", "周五", "周六"*/public static String getWeekOfDate(Date date) {String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};Calendar calendar = Calendar.getInstance();calendar.setTime(date);int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;if (week < 0)week = 0;return weekDays[week];}/*** 获取指定日期对应周几的序列** @param date 指定日期* @return 周一:1    周二:2    周三:3    周四:4    周五:5    周六:6    周日:7*/public static int getIndexWeekOfDate(Date date) {Calendar calendar = Calendar.getInstance();calendar.setTime(date);int index = calendar.get(Calendar.DAY_OF_WEEK);if (index == 1) {return 7;} else {return --index;}}/*** 获取当前月份*/public static int getNowMonth() {Calendar calendar = Calendar.getInstance();return calendar.get(Calendar.MONTH) + 1;}/*** 获取当前月号*/public static int getNowDay() {Calendar calendar = Calendar.getInstance();return calendar.get(Calendar.DATE);}/*** 获取当前年份*/public static int getNowYear() {Calendar calendar = Calendar.getInstance();return calendar.get(Calendar.YEAR);}/*** 获取本月份的天数*/public static int getNowDaysOfMonth() {Calendar calendar = Calendar.getInstance();return daysOfMonth(calendar.get(Calendar.YEAR), calendar.get(Calendar.DATE) + 1);}/*** 计算两个日期之间的年份差距** @param firstDate* @param secondDate* @return*/public static int getYearGapOfDates(Date firstDate, Date secondDate) {if (firstDate == null || secondDate == null) {return 0;}Calendar helpCalendar = Calendar.getInstance();helpCalendar.setTime(firstDate);int firstYear = helpCalendar.get(Calendar.YEAR);helpCalendar.setTime(secondDate);int secondYear = helpCalendar.get(Calendar.YEAR);return secondYear - firstYear;}/*** 计算两个日期之间的天数差** @param startDate* @param endDate* @return*/public static int getDaysGapOfDates(Date startDate, Date endDate) {int date = 0;if (startDate != null && endDate != null) {date = getDaysBetween(startDate, endDate);}return date;}/*** 计算两个日期之间的月份差距** @param firstDate* @param secondDate* @return*/public static int getMonthGapOfDates(Date firstDate, Date secondDate) {if (firstDate == null || secondDate == null) {return 0;}return (int) ((secondDate.getTime() - firstDate.getTime())/ ONE_DAY_MILLS / 30);}/*** 获取指定月份的天数** @param year  年份* @param month 月份* @return 对应天数*/public static int daysOfMonth(int year, int month) {switch (month) {case 1:case 3:case 5:case 7:case 8:case 10:case 12:return 31;case 4:case 6:case 9:case 11:return 30;case 2:if ((year % 4 == 0 && year % 100 == 0) || year % 400 != 0) {return 29;} else {return 28;}default:return -1;}}private static int getDaysBetween(Date startDate, Date endDate) {return (int) ((endDate.getTime() - startDate.getTime()) / ONE_DAY_MILLS);}
}

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
@SuppressWarnings(value = {"rawtypes"})
@Slf4j
public class OrderNumberUtils {@Autowired@Qualifier("redisTemplate")private RedisTemplate redisTemplate;/*** 对取值补 0** @param keyName* @param lenght  补足多少位* @return*/public String generateOrderNum(String keyName, int lenght) {Integer serialNumber = getSerialNumber(keyName);return String.format("%0" + lenght + "d", serialNumber);}/*** 数量自增 已设置过期时间** @param keyName* @return*/public Integer getSerialNumber(String keyName) {keyName = "SerialNumber:" + keyName;try {RedisAtomicLong entityIdCounter = new RedisAtomicLong(keyName, redisTemplate.getConnectionFactory());Long incr = entityIdCounter.getAndIncrement();if (null == incr || incr.longValue() == 0) {// 初始设置过期时间// 设置过期时间 24小时entityIdCounter.expire(24, TimeUnit.HOURS);// 这里取第二次 incr 就是从1开始了,默认从0开始incr = entityIdCounter.getAndIncrement();}log.debug(keyName + "==========" + incr);return incr.intValue();} catch (Exception e) {log.error("======redisIncr======", e);}return null;}
}

测试

  // 生成number指定长度   0000001、int leng = 6;String 年月日 = DateUtils.dateToString(new Date(), DateUtils.DateFormat.ALLTIME);String number = orderNumber.generateOrderNum(年月日, leng );System.out.println(年月日.concat( number));
订单结果
20230722114301000001
20230722114301000002
20230722114301000003
20230722114301000004
20230722114301000005
20230722114302000001
20230722114302000002
20230722114302000004

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/5669.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react 实现小球加入购物车动画

代码 import React, { useRef } from react;const ProductLayout () > {const box useRef(null);const createBall (left, top) > {const ball document.createElement(div);ball.style.position absolute;ball.style.left left - 10 px;ball.style.top top - 1…

【机器学习】了解 AUC - ROC 曲线

一、说明 在机器学习中&#xff0c;性能测量是一项基本任务。因此&#xff0c;当涉及到分类问题时&#xff0c;我们可以依靠AUC - ROC曲线。当我们需要检查或可视化多类分类问题的性能时&#xff0c;我们使用AUC&#xff08;曲线下面积&#xff09;ROC&#xff08;接收器工作特…

使用 Vue 创建一个简单的 Loading 动画

使用 Vue 创建一个简单的 Loading 动画 1. 开始之前 确保 正确安装了 Vue 3知道如何启动一个新的 Vue 项目&#xff08;或在项目中使用Vue&#xff09;了解 Vue 3 的 Composition API&#xff08;本文将使用&#xff09; 2. 设计组件 该组件应该包含三个部分 控制逻辑旋转…

win10 安装 langchain-chatglm 遇到的问题

win10 安装 langchain-chatglm 避坑指南&#xff08;2023年6月21日最新版本&#xff09;_憶的博客-CSDN博客官网看起来安装很简单&#xff0c;网上教程也是&#xff0c;但实际上我耗费了两天时间&#xff0c;查阅了当前网络上所有可查阅的资料&#xff0c;重复「安装-配置-卸载…

Spring Security 构建基于 JWT 的登录认证

一言以蔽之&#xff0c;JWT 可以携带非敏感信息&#xff0c;并具有不可篡改性。可以通过验证是否被篡改&#xff0c;以及读取信息内容&#xff0c;完成网络认证的三个问题&#xff1a;“你是谁”、“你有哪些权限”、“是不是冒充的”。 为了安全&#xff0c;使用它需要采用 …

HideSeeker论文阅读

文章目录 3.1 Overview of Our System HideSeeker3.2 Visual Information Extraction3.3 Relation Graph Learning3.4 Hidden Object Inference 4 EVALUATIONS4.7 Summary 6 DISCUSSIONS AND CONCLUSION 3.1 Overview of Our System HideSeeker 我们设计了一种名为“HideSeeke…

个人博客系统(SSM版 前端+后端)

前言 在学习Servlet的时候,也写了一个博客系统,主要的就是使用servelet加Tomcat进行实现的,而这个项目 仅仅适合去学习Web项目开发的思想,并不满足当下企业使用框架的思想,进行学习过Spring,Spring Boot,Spring MVC以及MyBatis之后,我们就可以对之前的项目使用SSM框架的形式进行…

95、Kafka是pull?push?优劣势分析

Kafka是pull&#xff1f;push&#xff1f;优劣势分析 一、pull模式二、push模式三、额外补充 一、pull模式 根据consumer的消费能力进行数据拉取&#xff0c;可以控制速率可以批量拉取、也可以单条拉取可以设置不同的提交方式&#xff0c;实现不同的传输语义 缺点: 如果kafka…

webpack环境配置的问题

1.如何区分不同的配置 // vue.config.js 中定义不同配置项 module.exports {// 默认配置// ...// 开发环境配置dev: {// ...},// 生产环境配置prod: {// ...} };// 在运行 vue-cli-service 命令时&#xff0c;在package.json中设置不同配置 {"scripts": {"ser…

react+redux异步操作数据

reactredux异步操作数据 redux中操作异步方法&#xff0c;主要是&#xff1a; 1、借助createAsyncThunk()封装异步方法&#xff1b;2、通过extraReducers处理异步方法触发后的具体逻辑&#xff0c;操作派生的state 1、异步操作的slice import { createSlice, createAsyncThunk…

uniapp 之 微信小程序、支付宝小程序 对于自定义导航栏的不同

目录 前言 微信小程序 代码 支付宝小程序 首页配置文件 二级菜单页面 配置 总结 不同 相同 前言 小程序都是 uni-app 写的 不是原生 微信小程序 代码 pages.json文件中配置 重点&#xff1a; "navigationStyle": "custom", // 导航栏样式…

【N32L40X】学习笔记05-串口库(空闲中断+接收非空中断)

串口 该函数库的目的就是在统一的地方配置&#xff0c;将配置的不同项放置在一个结构体内部使用一个枚举来定义一个的别名 bsp_uart.h #ifndef _BSP_UART_H_ #define _BSP_UART_H_ #include<stdio.h> #include<stdint.h> #include "n32l40x.h"#define…

ChatGPT开放自定义系统级别的指令,可设置偏好变成专属助理

OpenAI官方消息https://openai.com/blog/custom-instructions-for-chatgpt OpenAI为其大型语言模型接口ChatGPT引入了自定义指令&#xff0c;旨在为用户提供更加量身定制和个性化的体验&#xff0c;可以设置您的偏好&#xff0c;ChatGPT将在未来的所有对话中记住它们。 该功…

Redis高可用部署架构

目录 1. 主从复制与哨兵架构&#xff1a;2. Redis集群架构&#xff1a; Redis高可用部署可以采用主从复制与哨兵架构或Redis集群架构。下面将分别介绍这两种架构的架构图、优缺点和具体应用场景。 1. 主从复制与哨兵架构&#xff1a; 架构图&#xff1a; ----------| Client…

Python—数据结构(一)

先放一张自己学习和整理归纳的思维导图&#xff0c;以便让大家都知道我自己的整体学习路线。 数据结构的学习路上内容枯燥&#xff0c;但坚持下来一定有很大的收获&#xff01;加油&#x1f4aa;&#x1f3fb;&#xff01; 数据结构 数据的概念数据元素&#xff1a; 若干基本…

Go语言通过反射获取各种类型变量的值

Go语言通过反射获取各种类型变量的值 反射是程序在运行期间获取变量的类型和值、或者执行变量的方法的能力。 1、什么是反射 反射是程序在运行期间获取变量的类型和值、或者执行变量的方法的能力。 Golang 反射包中有两对非常重要的函数和类型&#xff0c;两个函数分别是&a…

音视频开发-ffmpeg介绍-系列二

目录 一、FFmpeg核心结构体 二、解码流程 三、FFmpeg解码实现 四、FFmpeg编码实现 五、FFmpeg转码实现 一、FFmpeg核心结构体 AVFormatContext&#xff1a;解封装功能的结构体&#xff0c;包含文件名、音视频流、时长、比特率等信息&#xff1b; AVCodecContext&#xf…

【算法基础:数学知识】4.3 欧拉函数

文章目录 欧拉函数定义性质 例题列表873. 欧拉函数&#xff08;使用质因数分解求一个数的欧拉函数&#xff09;原理讲解&#xff08;公式推导&#xff09;⭐解法代码 874. 筛法求欧拉函数&#xff08;求 1 ~ n 中所有数字的欧拉函数&#xff09;⭐ 欧拉函数 https://oi-wiki.o…

[数据结构 -- 手撕排序算法第六篇] 递归实现快速排序(集霍尔版本,挖坑法,前后指针法为一篇的实现方法,很能打)

目录 1、常见的排序算法 1.1 交换排序基本思想 2、快速排序的实现方法 2.1 基本思想 3 hoare&#xff08;霍尔&#xff09;版本 3.1 实现思路 3.2 思路图解 3.3 为什么实现思路的步骤2、3不能交换 3.4 hoare版本代码实现 3.5 hoare版本代码测试 4、挖坑法 4.1 实现…

Java设计模式解析:迭代器模式的实现与应用

迭代器模式是一种行为型设计模式&#xff0c;它提供了一种统一的方式来遍历集合中的元素&#xff0c;而无需暴露集合的内部结构。在本文中&#xff0c;我们将深入探讨迭代器模式的实现和应用。 在软件开发中&#xff0c;集合是一种常见的数据结构&#xff0c;用于存储和管理一…