在開發中,遇到這樣一個需求,在介質資料新增時,需要生成一個介質編號,格式為"JZ+yyyyMMDD+4位遞增數字"
先是使用百度找尋解決方法,解決方法
里面的查詢快取的方法在我這專案里沒有,我也不會寫,就自己想了個折中的方法,再請求這個介面的時候,先去資料庫查詢MAX(id),如果有,就在此基礎上+1
如果沒有,就初始化一個值1進行傳參,相關代碼如下:
點擊查看代碼
public class NumberUtils {
/**
* 生成14位唯一流水號,"JZ"+yyyyMMdd+4位數字
* 4位數字,如:0001
* @return
*/
@NotNull
public static String generateSerialNum(String str, Integer nowNum){
// 定義需要回傳的流水號
String serialNum;
// 先查詢到今天的日期,格式:"yyyyMMdd"
String todayDate = new SimpleDateFormat("yyyyMMdd")
.format(new Date());
// 固定字母前綴 拼接 今天日期,組成新的完整的前綴
String prefixCode = str + todayDate;
serialNum = getCode(prefixCode, nowNum);
return serialNum;
}
/**
* 將數值拼接成對應的位數
* @param prefix 前綴:"JZ"+yyyyMMdd
* @param nowNum 當前要生成的數字
* @return 拼接好的流水號
*/
private static String getCode(String prefix,int nowNum ) {
// 需要回傳的code
StringBuilder code = new StringBuilder();
// 需要拼接的數字
StringBuilder num = new StringBuilder();
// 封裝的數字物件,里面 value 加了 volatile關鍵字,保證了執行緒安全
AtomicInteger count = new AtomicInteger(nowNum);
// 將數值補足為4位字串
if (count.get() < 10) {
num.append("000").append(count.get());
} else if(count.get() < 100){
num.append("00").append(count.get());
}else if(count.get() < 1000){
num.append("0").append(count.get());
} else if (count.get() >= 1000) {
num.append(count.get());
}
// 先拼接前綴
code.append(prefix);
// 再拼接數字
code.append(num);
return code.toString();
}
}
后面被說不行,并發下不行,而且跟資料庫連接效率也低,就想到了使用redis的incr方法,相關代碼如下:
點擊查看代碼
public class NumberUtils {
/**
* 編號自動生成
* @param redisTemplate redis模板
* @param code 前綴 首字母大寫
* @param dateFormat 日期格式
* @param nums 幾位數字
* @return 編號
*/
@NotNull
public static String generateSerialNum(@NotNull RedisTemplate<String,Integer> redisTemplate,
String code, String dateFormat, Integer nums) {
// 使用StringBuilder拼接字串
StringBuilder sb = new StringBuilder();
// 獲取當前時間并定義日期格式
String localDateFormat = DateUtils.localDateFormat(LocalDate.now(), dateFormat);
sb.append(code);
sb.append(localDateFormat);
// 將拼接好的字串做key,獲取redis中的資料
Integer i = redisTemplate.opsForValue().get(sb.toString());
int increment;
if (i != null) {
// 如果redis中有資料,則使用increment()將資料+1
increment = Objects.requireNonNull(redisTemplate.opsForValue()
.increment(sb.toString())).intValue();
} else {
// 如果redis中沒有資料,則使用setIfAbsent()將資料設定為1
increment = 1;
redisTemplate.opsForValue().setIfAbsent(sb.toString(),increment);
}
// 第一次format格式化nums位0,之后再格式化increment
sb.append(String.format(String.format("%%0%dd", nums), increment));
return sb.toString();
}
}
然后說代碼邏輯沒問題,就是代碼可以再優化,一通解釋加我一通操作,最后代碼如下:
點擊查看代碼
@Slf4j
public class NumberUtils {
private NumberUtils() {}
/**
* 編號自動生成
*
* @param redisTemplate redis模板
* @param code 前綴 首字母大寫
* @param dateFormat 日期格式
* @param nums 幾位數字
* @return 編號
*/
@NotNull
public static String generateSerialNum(RedisTemplate<String,Integer> redisTemplate,
String code, String dateFormat, Integer nums) {
// nums位數字,不夠的前面補0
val format = String.format("%%0%dd", nums);
// 回傳拼接好的編號
return code + DateUtils.localDateFormat(LocalDate.now(), dateFormat)
+ String.format(format, getIncrement(redisTemplate, code + dateFormat));
}
private static Integer getIncrement(@NotNull RedisTemplate<String,Integer> redisTemplate, String redisKey) {
return Optional.ofNullable(redisTemplate.opsForValue().get(redisKey))
// 回傳redis里的值 + 1
.map(num -> Objects.requireNonNull(redisTemplate.opsForValue().increment(redisKey)).intValue())
// 如果redis里沒有,則插入1并通過判斷插入是否成功來回傳初始化值1,如果插入失敗,則回傳拼接null
.orElse(Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(redisKey, 1)) ? 1 : null);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/472247.html
標籤:其他
