在项目中,我们经常遇到需要生成订单编号、字典编号等唯一值场景,大部分的服务器环境都是负载均衡,多台机器,那么此时我们必须考虑多并发的问题,所以需要借助redis来实现编号生成的功能。
我的实现思路是redis锁限制为单线程模式,防并发,再获取redis编号key,进而分配到最新的编号。
GenerateCaseNumberUtil.java代码如下:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @FileName: GenerateCaseNumber
* @Description: 生成案件编号,生成规则:LD/XZ/MS/SS/XS (2位)+年(4位)+自增序列号(5位)共11位
* @author: v-guoxingliang.ea
* @create: 2018-07-09 17:26
* @Copyright: (c) 2018年 ****公司
*/
@Slf4j
@Component
public class GenerateCaseNumber {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private RedissonClient client;
/**
* <p>Description: [
* 生成案件编号,生成规则:
* LD/XZ/MS/SS/XS (2位)+年(4位)+自增序列号(5位)共11位
* 劳动争议案件类型:LD
* 行政诉讼案件类型:XZ
* 民事诉讼案件类型:MS
* 商事诉讼案件类型:SS
* 刑事诉讼案件类型:XS]</p>
* Created on: 2018/9/3 16:49
* @author v-guoxingliang.ea
* @param caseType LD/XZ/MS/SS/XS
* @return java.lang.String
*/
public String getCaseNumber(String caseType) throws VerifyException {
RLock lock = client.getLock(RedisConstantUtil.REDIS_CASE_NUMBER_GENERATE_LOCK);
try {
lock.lock(10, TimeUnit.SECONDS);
String date = new SimpleDateFormat("yyyy").format(new Date());
String seq = seqGenerator(new SimpleDateFormat("yyyy").format(new Date()), 5, 1, RedisConstantUtil.REDIS_CASE_NUMBER_GENERATE);
return caseType + date + seq;
} catch (Exception e) {
log.warn("caseType=[{}]", caseType, e);
throw new VerifyException(LanguageUtil.get(ConstantsUtils.GENERATE_CASE_NUMBER_ERROR_MSG));
} finally {
lock.unlock();
}
}
/**
* <p>Description: [自增序列号]</p>
* Created on: 2018/7/31 14:51
* @author v-guoxingliang.ea
* @param prefix 前缀
* @param numLength 要生成多少位的数字
* @param startNum 起始数字
* @return java.lang.String
*/
public String seqGenerator(String prefix, int numLength, int startNum, String key) {
String upperCode = "";
//查找以prefix作为key值的数据长度
Long size = redisTemplate.opsForList().size(key);
//有数据
if (size > 0) {
//获取该key下面的所有值 (-1所有值;1下一个值)
List all = redisTemplate.opsForList().range(key, 0, -1);
//返回最后一个值
upperCode = all.get(all.size() - 1).toString();
}
String returnCode = "";
//后缀数字
int suffix;
if (!StringUtils.isEmpty(upperCode)) {//有数据
//截取前缀开始的后面数字
suffix = Integer.parseInt(upperCode);
//最后的序号加一
suffix++;
} else {//没有数据
suffix = startNum;
}
//后缀不够numLength长,前面补充0
String str = "%0" + numLength + "d";
returnCode = String.format(str, suffix);
//存入Redis
redisTemplate.opsForList().rightPush(key, returnCode);
return returnCode;
}
}
常量类RedisConstantUtil.java代码如下:
public class RedisConstantUtil {
private RedisConstantUtil() {}
/*生成案件编码key */
public static final String REDIS_CASE_NUMBER_GENERATE = "case:generate:caseNumber:";
public static final String REDIS_CASE_NUMBER_GENERATE_LOCK = "case:generate:caseNumber:lock";
}
上述用到的redis的jar包:
<!-- 集成了redis这个jar就不要重复引入了 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.13.RELEASE</version>
</dependency>
<!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.9.1</version>
</dependency>
其中VerifyException是自定义异常。
转载:https://blog.csdn.net/qq_16207635/article/details/101205695
查看评论