批量生成流水号java
业务码+秒级时间戳+((userId+随机数)加密)
生成流水号(格式:业务码+时间+当天自增号)
业务码+日级时间戳+(查询数据库自增)
业务码+日级时间戳+(查询缓存自增)
key为(业务码+日级时间戳)
过期时间为当天的剩余时间
业务码+日级时间戳+(查询缓存自增) 实现代码
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.concurrent.TimeUnit;
/**
* 生成流水线单号格式:业务码+yyyyMMdd+数字
* 例如: LSH2022102700001
*
* @author lyn
*/
@Component
public class SerialNoUtils {
/**
* 订单类别头
*/
public static final String ORDER_CODE = "DD-";
/**
* 退货类别头
*/
public static final String RETURN_ORDER = "THD-";
/**
* 退款类别头
*/
public static final String REFUND_ORDER = "TKD-";
/**
* 序号长度
*/
public static final int SORT_LENGTH = 6;
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
/**
* 生成17位唯一流水号,"LSH"+yyyyMMdd+6位数字
* 6位数字,如:000001
*
* @param bizCode 业务码
* @return
*/
public String generateSerialNo(String bizCode) {
//定义需要返回的流水号
String serialNo = null;
//先查询到今天的日期,格式:"yyyyMMdd"
String todayDate = new SimpleDateFormat("yyyyMMdd")
.format(new Date());
//固定字母前缀 拼接 今天日期,组成新的完整的前缀,也就是缓存的key
String cacheKey = bizCode + todayDate;
RLock lock = redissonClient.getLock("SerialNoLock" + cacheKey);
//通过key查询缓存有没有num数据,没有赋初始值并设置过期时间
try {
lock.lock();
if (Boolean.FALSE.equals(redisTemplate.hasKey(cacheKey))) {
redisTemplate.opsForValue().set(cacheKey, "0", getSeconds(), TimeUnit.SECONDS);
}
//再通过key查询缓存有没有num数据,缓存操作根据自身项目封装工具类
String value = redisTemplate.opsForValue().get(cacheKey);
Long codeNum = null;
//如果缓存查询有值,数值+1,再赋值给下一个流水号
if (null != value) {
codeNum = Long.parseLong(value) + 1L;
} else {
//如果缓存查询没值,直接赋值为1
codeNum = 1L;
}
//流水号 = 缓存key + 拼接的数值 = 前缀 + 日期 + 拼接的数值
serialNo = getCodeOfSix(cacheKey, codeNum.intValue());
//设置缓存,调用此方法,会自动将key所对应的value+1,保存时长:今天剩余的时间
redisTemplate.opsForValue().increment(cacheKey, 1);
} finally {
lock.unlock();
}
return serialNo;
}
/**
* 将数值拼接成对应的位数
*
* @param prefix 前缀:"LSH"+yyyyMMdd
* @param nowNum 当前要生成的数字
* @return 拼接好的流水号
*/
private String getCodeOfSix(String prefix, int nowNum) {
//需要拼接的数字
StringBuilder numSb = new StringBuilder(prefix);
//补零
int num = SORT_LENGTH - String.valueOf(nowNum).length();
for (int i = 0; i < num; i++) {
numSb.append("0");
}
numSb.append(nowNum);
return numSb.toString();
}
/**
* 获取当天结束还剩余多少秒
*
* @return
*/
private static int getSeconds() {
//获取今天当前时间
Calendar curDate = Calendar.getInstance();
//获取明天凌晨0点的日期
Calendar tomorrowDate = new GregorianCalendar(
curDate.get(Calendar.YEAR),
curDate.get(Calendar.MONTH),
curDate.get(Calendar.DATE) + 1,
0, 0, 0);
//返回 明天凌晨0点 和 今天当前时间 的差值(秒数)+1000(防止提前失效)
return (int) (tomorrowDate.getTimeInMillis() - curDate.getTimeInMillis()) / 1000 + 1000;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~