Author:赵志乾
Date:2020-06-05
Declaration:All Right Reserved!!!
踩坑:
场景:业务记录需要唯一标识,也就是我们使用的业务id。
做法:本地通过时间戳+业务串+随机数的规则生成业务id,当在循环中使用该方法是会产生重复的业务id。代码如下:
public class ServiceIdGenerator {
private static DateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmssSSS", Locale.CHINA);
// 产生随机Id串--时间+业务标识+"R"+随机数
public static String generateRandomIdStr(String serviceFlag) {
// step1: 业务标识为空时默认使用UN
serviceFlag = StringUtils.isBlank(serviceFlag) ? "UN" : serviceFlag;
// step2: 时间+业务标识+"R"
StringBuilder serviceId = new StringBuilder(serviceFlag.length() + 21);
serviceId.append(dateFormat.format(new Timestamp(System.currentTimeMillis())));
serviceId.append(serviceFlag);
serviceId.append("R");
// step3: 拼接随机数
Random random = new Random();
DecimalFormat decimalFormat = new DecimalFormat("000000");
serviceId.append(decimalFormat.format((long)random.nextInt(1000000)));
return serviceId.toString();
}
}
业务id需要唯一,通常会在数据库字段上设置唯一键。当产生重复业务id时,会导致数据入库失败。
解决方案:
基于Redis实现顺序id。规则如下:时间戳+业务串+顺序号。顺序号基于Redis自增获取,保证全局唯一。代码如下:
public class ServiceIdGenerator {
private static DateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmssSSS", Locale.CHINA);
private static DecimalFormat decimalFormat = new DecimalFormat("000000");
private static JedisTemplate jedisTemplate;
private static final String ID_KEY = "test.serviceId.generator.idkey";
// 产生随机Id串--时间+业务标识+"R"+随机数
public static String generateRandomIdStr(String serviceFlag) {
// step1: 业务标识为空时默认使用UN
serviceFlag = StringUtils.isBlank(serviceFlag) ? "UN" : serviceFlag;
// step2: 时间+业务标识+"R"
StringBuilder serviceId = generateServiceIdPrefix(serviceFlag,"R");
// step3: 拼接随机数
Random random = new Random();
serviceId.append(decimalFormat.format((long)random.nextInt(1000000)));
return serviceId.toString();
}
private static StringBuilder generateServiceIdPrefix(String serviceFlag,String type){
StringBuilder serviceId = new StringBuilder(serviceFlag.length() + 21);
serviceId.append(dateFormat.format(new Timestamp(System.currentTimeMillis())));
serviceId.append(serviceFlag);
serviceId.append(type);
return serviceId;
}
// 产生顺序Id串--时间+业务标识+"S"+顺序号
public static String generateSeqIdStr(String serviceFlag) {
// step0: 初始化
initServiceIdGenerator();
// step1: 业务标识为空时默认使用UN
serviceFlag = StringUtils.isBlank(serviceFlag) ? "UN" : serviceFlag;
// step2: 时间+业务标识+"S"
StringBuilder serviceId = generateServiceIdPrefix(serviceFlag,"S");
// step2: 获取序列号
Integer currentId = jedisTemplate.incrBy(ID_KEY,1);
if (currentId == null) {
// 有问题的情况下再转回随机id
return generateRandomIdStr(serviceFlag);
}
// step3: 生成业务号
serviceId.append(decimalFormat.format(currentId & 65535));
return serviceId.toString();
}
private static void initServiceIdGenerator() {
if (jedisTemplate == null) {
synchronized (IDGenerator.class) {
if (jedisTemplate == null) {
jedisTemplate = JedisTemplate.use();
Integer id = jedisTemplate.getAsInt(ID_KEY);
if (id == null) {
jedisTemplate.set(ID_KEY, "0");
}
}
}
}
}
}