buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

这儿有一个基于redis生成订单流水号的工具,拿走不谢!

 

 1 import cn.hutool.core.util.RandomUtil;
 2 import cn.hutool.core.util.StrUtil;
 3 import lombok.extern.slf4j.Slf4j;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.data.redis.core.RedisTemplate;
 6 import org.springframework.data.redis.core.script.DefaultRedisScript;
 7 import org.springframework.lang.Nullable;
 8 import org.springframework.stereotype.Component;
 9 
10 import java.time.LocalDateTime;
11 import java.time.format.DateTimeFormatter;
12 import java.util.Collections;
13 import java.util.concurrent.TimeUnit;
14 
15 /**
16  * 生成订单流水号18  * 精确到秒级,后面加随机数(redis获取)
19  * <p>
20  * 变更记录:2023-12-13 14:10 gz.zhang 通过增加随机性,修正因宿主机时钟回拨导致生成重复值的bug
21  * 变更记录:2023-12-19 14:37 刘红洁/张国战 ①key改为按日期,最后的拼接用取模的方式防止数据越界,②解决concat带来的bug。
22  *
23  * @author wangzaizhou
24  */
25 @Component
26 @Slf4j
27 public class GenerateOrderIdUtil {
28     private static final String DEFAULT_KEY_PREFIX = "keyPrefix";
29     private static RedisTemplate<String, Object> stringObjectRedisTemplate;
30 
31     @Autowired
32     public void setRedisUtil(RedisTemplate<String, Object> redisTemplate) {
33         stringObjectRedisTemplate = redisTemplate;
34     }
35 
36     /**
37      * 订单流水号组成: 时间秒 + 5位数(redis计算后的)
38      *
39      * @param keyPrefix redis key的前缀标识,可以指定为 系统标识(如“Channel”),也可以指定为业务标识(如“Pay”),或者具体数据标识(如“PayPaymentFlow”),etc.,也可为空
40      * @return 2021030914590406391
41      */
42     public static long genOrderId(@Nullable String keyPrefix) {
43         if (StrUtil.isBlank(keyPrefix)) {
44             keyPrefix = DEFAULT_KEY_PREFIX;
45         }
46         LocalDateTime now = LocalDateTime.now();
47         String redisKey = keyPrefix + now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
48         Long incrValue = null;
49         try {
50             incrValue = stringObjectRedisTemplate.execute(REDIS_SCRIPT, Collections.singletonList(redisKey), TimeUnit.HOURS.toSeconds(24));
51         } catch (Exception e) {
52             log.error("GenerateOrderIdUtil 生成订单流水号异常,keyPrefix={}", keyPrefix, e);
53         }
54         if (incrValue == null) incrValue = RandomUtil.randomLong(99999);
55         String orderIdPrefix = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
56         String orderId = String.format("%s%05d", orderIdPrefix, incrValue % 100000);
57         return Long.parseLong(orderId);
58     }
59 
60     /**
61      * 订单流水号组成: 时间秒 + 5位数(redis计算后的)
62      *
63      * @return 2021030914590406391
64      */
65     public static long genOrderId() {
66         return genOrderId(DEFAULT_KEY_PREFIX);
67     }
68 
69     private final static DefaultRedisScript<Long> REDIS_SCRIPT = new DefaultRedisScript<>(
70             "local key = KEYS[1]\n" +
71                     "local expiration_time = (ARGV[1])\n" +
72 
73                     "local current_value = redis.call('INCRBY', key, 1)\n" +
74                     "if current_value == 1 then\n" +
75                     "  redis.call('EXPIRE', key, expiration_time)\n" +
76                     "end\n" +
77                     "return current_value\n"
78             , Long.class);
79 
80 }

 

posted on 2023-12-19 19:57  buguge  阅读(104)  评论(0编辑  收藏  举报