• 基于redis实现分布式id


    基于订单生成规则,期望是以年与日+随机串进行生成规则,因为分布式,所以对自增id场景需要,所以存在分布式自增id场景

    直接上代码

    @Slf4j
    @Service
    public class CommonLocalCacheService {
        @Autowired
        private RedisTemplate redisTemplate;
        /**
         * 锁对象
         */
        private static final Object LOCK = new Object();
    
        /**
         * 本地缓存redis自增序列,例如:key:value=20211104:【1-10000】
         */
        private static final Cache<String, Optional<RedisSequence>> REDIS_SEQUENCE_CACHE = CacheBuilder.newBuilder()
                .expireAfterWrite(1, TimeUnit.DAYS)
                .build();
    
        /**
         * 获取redis自增Key,
         * 分布式id生成规则:
         * 根据日期 : 年+月+日 + 3位随机字符串 + 7位redis自增key
         * 取redis key 为   20211109,每次取10000,本地缓存下来,后续如果达到最大值,网上递增10000
         * 【1-10000】   20211109xxx0000001
         */
        @SneakyThrows
        public String generatorId() {
            String sequenceKey = DateUtils.parseTime(LocalDateTime.now(), DateUtils.TimeFormat.SHORT_DATE_PATTERN_NONE);
            StringBuilder orderId = new StringBuilder(sequenceKey);
            // 如果达到最大批次,换一批
            synchronized (LOCK) {
                //缓存时长为当前时间+1天
                Optional<RedisSequence> redisSequenceOptional = getLocalRedisSequence(sequenceKey, 10000, DateUtils.addDays(DateUtils.now(), 1));
                // 如果缓存为空,则redis挂了,随机字段
                if (!redisSequenceOptional.isPresent()) {
                    for (int i = 0; i < 10; i++) {
                        orderId.append(RandomUtils.nextInt(0, 10));
                    }
                    return orderId.toString();
                }
                RedisSequence redisSequence = redisSequenceOptional.get();
                if (redisSequence.getStartSequence().get() == redisSequence.getEndSequence().get()) {
                    //如果值相等则失效,重新获取
                    log.info("----------------------------invalidate---------start:{}, end:{}", redisSequence.getStartSequence(), redisSequence.getEndSequence());
                    REDIS_SEQUENCE_CACHE.invalidate(sequenceKey);
                    return generatorId();
                }
                redisSequence.getStartSequence().getAndAdd(1L);
                REDIS_SEQUENCE_CACHE.put(sequenceKey, Optional.of(redisSequence));
                String sequence = String.format("%1$07d", redisSequence.getStartSequence().get());
                //中间3位随机数
                for (int i = 0; i < 3; i++) {
                    orderId.append(RandomUtils.nextInt(0, 10));
                }
                orderId.append(sequence);
            }
            log.info("orderId is {}", orderId.toString());
            return orderId.toString();
        }
    
        /**
         * 从本地缓存中取redisSequence
         *
         * @param sequenceKey
         * @return
         */
        private Optional<RedisSequence> getLocalRedisSequence(String sequenceKey, int increment, Date expireTime) {
            try {
                return REDIS_SEQUENCE_CACHE.get(sequenceKey, () -> {
                    RedisAtomicLong counter = new RedisAtomicLong(RedisConstants.GOODS_GENERATOR_ORDER_ID.concat(sequenceKey), redisTemplate.getConnectionFactory());
                    counter.expireAt(expireTime);
                    long end = counter.addAndGet(increment);
                    RedisSequence redisSequence = RedisSequence.builder().startSequence(new AtomicLong(end-increment)).endSequence(new AtomicLong(end)).build();
                    log.info("----------------------------get---------start:{}, end:{}", redisSequence.getStartSequence(), redisSequence.getEndSequence());
                    return Optional.of(redisSequence);
                });
            } catch (Exception e) {
                log.error("getLocalRedisSequence is errored, sequenceKey:{}, increment:{}", sequenceKey, increment, e);
            }
            return Optional.empty();
        }
    
    }

     

    //日期工具类
    public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    
        private static final String YEAR_TO_SECOND_PATTERN = "yyyyMMddHHmmss";
        /**
         * 获取默认时间格式: yyyy-MM-dd HH:mm:ss
         */
        private static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = TimeFormat.LONG_DATE_PATTERN_LINE.formatter;
    
        private DateUtils() {
            //工具类不应该有可用的构造方法
        }
    
        /**
         * 计算指定日期的生日
         *
         * @param credentialNo 身份证号
         * @param someDay      指定日期
         * @return 岁数
         */
        public static int getAge(String credentialNo, LocalDate someDay) {
            LocalDate birthDate = getBirthDay(credentialNo);
            return Period.between(birthDate, someDay).getYears();
        }
    
        /**
         * 计算当前年龄
         * @param credentialNo 身份证号
         * @return 岁数
         */
        public static int getAge(String credentialNo) {
            LocalDate birthDate = getBirthDay(credentialNo);
            return Period.between(birthDate, LocalDate.now()).getYears();
        }
    
        /**
         * 计算今天的生日
         *
         * @param credentialNo 身份证号
         * @return 岁数
         */
        public static int getAgeToday(String credentialNo) {
            LocalDate birthDate = getBirthDay(credentialNo);
            return Period.between(birthDate, LocalDate.now()).getYears();
        }
    
        /**
         * 计算明天的生日
         *
         * @param credentialNo 身份证号
         * @return 岁数
         */
        public static int getAgeTomorrow(String credentialNo) {
            LocalDate birthDate = getBirthDay(credentialNo);
            return Period.between(birthDate, LocalDate.now().plusDays(1)).getYears();
        }
    
        private static LocalDate getBirthDay(String credentialNo) {
            String birthdayStr;
            if (credentialNo.length() == 15) {
                birthdayStr = "19" + credentialNo.substring(6, 12);
            } else if (credentialNo.length() == 18) {
                birthdayStr = credentialNo.substring(6, 14);
            } else {
                throw new IllegalArgumentException("credentialNo's length is not 15 or 18!");
            }
            return LocalDate.parse(birthdayStr, DateTimeFormatter.ofPattern("yyyyMMdd"));
        }
    
        public static Date now() {
            return new Date();
        }
    
        public static Long stringToEpochSecond(String dateStr) {
            return parseDate(dateStr).toInstant().getEpochSecond();
        }
    
        /**
         * 格式化日期: 精确到秒
         */
        public static String getCurrentTimeStr() {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YEAR_TO_SECOND_PATTERN);
            return LocalDateTime.now().format(formatter);
        }
    
        /**
         * 格式化日期: 精确到日
         */
        public static String formatDateStr(Date date) {
            return DateFormatUtils.format(date, "yyyyMMdd");
        }
    
        /**
         * 解析日期yyyyMMddHHmmss为LocalDateTime
         */
        public static LocalDateTime parseLocalDateTime(String dateStr) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YEAR_TO_SECOND_PATTERN);
            return LocalDateTime.parse(dateStr, formatter);
        }
    
        /**
         * 解析日期yyyyMMddHHmmss为Date
         */
        @SneakyThrows
        public static Date parseDate(String dateStr) {
            return org.apache.commons.lang3.time.DateUtils.parseDate(dateStr, YEAR_TO_SECOND_PATTERN);
        }
    
        /**
         * 格式化为db格式: 20170911000000 -> 2017-09-11 00:00:00
         */
        @SneakyThrows
        public static String formatDbDateStr(String dateTime) {
            Date date = org.apache.commons.lang3.time.DateUtils.parseDate(dateTime, YEAR_TO_SECOND_PATTERN);
            return DateFormatUtils.format(date, "yyyy-MM-dd HH:mm:ss");
        }
    
        public static String getYearAndMonth(Date date) {
            return DateFormatUtils.format(date, "yyyyMM");
        }
    
        @SneakyThrows
        public static String formatChineseDateStr(String dateTime) {
            Date date = parseDate(dateTime);
            return DateFormatUtils.format(date, "yyyy年MM月dd日");
        }
    
        public static Long utcFromDate(String dateTime, String... dateFormat) {
            String defaultDateFormat = YEAR_TO_SECOND_PATTERN;
            if (dateFormat != null && dateFormat.length > 0) {
                defaultDateFormat = dateFormat[0];
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(defaultDateFormat);
            return LocalDateTime.parse(dateTime, formatter).atZone(ZoneId.systemDefault()).toEpochSecond();
        }
    
        /**
         * String 转时间
         *
         * @param timeStr
         * @return
         */
        public static LocalDateTime parseTime(String timeStr) {
            return LocalDateTime.parse(timeStr, DEFAULT_DATETIME_FORMATTER);
        }
    
        /**
         * String 转时间
         *
         * @param timeStr
         * @param format  时间格式
         * @return
         */
        public static LocalDateTime parseTime(String timeStr, TimeFormat format) {
            return LocalDateTime.parse(timeStr, format.formatter);
        }
    
        /**
         * 判断日期是否今天
         * @param date
         * @return
         */
        public static boolean isToday(Date date){
            return dateToLocalDateTime(date).isAfter(dateToLocalDateTime(localDateToDate(LocalDate.now())));
        }
    
    
    
        /**
         * 时间转 String
         *
         * @param time
         * @return
         */
        public static String parseTime(LocalDateTime time) {
            return DEFAULT_DATETIME_FORMATTER.format(time);
        }
    
        /**
         * 时间转 String
         *
         * @param time
         * @param format 时间格式
         * @return
         */
        public static String parseTime(LocalDateTime time, TimeFormat format) {
            return format.formatter.format(time);
        }
    
        /**
         * 获取当前时间
         *
         * @return
         */
        public static String getCurrentDateTime() {
            return DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.now());
        }
    
        /**
         * 获取当前时间
         *
         * @param format 时间格式
         * @return
         */
        public static String getCurrentDateTime(TimeFormat format) {
            return format.formatter.format(LocalDateTime.now());
        }
    
    
        /**
         * 当天时间起始点.
         *
         * @param date the date
         * @return the start date
         */
        public static LocalDateTime getStartDate(LocalDateTime date) {
            return string2LocalDateTime(date2String(date, TimeFormat.LONG_DATE_BEGIN_PATTERN_LINE));
        }
    
        /**
         * 当天时间终点.
         *
         * @param date the date
         * @return the end date
         */
        public static LocalDateTime getEndDate(LocalDateTime date) {
            return string2LocalDateTime(date2String(date, TimeFormat.LONG_DATE_END_PATTERN_LINE));
        }
    
        /**
         * String 转时间
         * @param timeStr
         * @return
         */
        public static LocalDateTime string2LocalDateTime(String timeStr) {
            return LocalDateTime.parse(timeStr, DEFAULT_DATETIME_FORMATTER);
        }
    
        /**
         * String 转时间
         * @param timeStr
         * @return
         */
        public static LocalDate string2LocalDate(String timeStr, TimeFormat timeFormat) {
            return LocalDate.parse(timeStr, timeFormat.formatter);
        }
    
        /**
         * String 转时间
         *
         * @param timeStr
         * @param format  时间格式
         * @return
         */
        public static LocalDateTime string2LocalDateTime(String timeStr, TimeFormat format) {
            return LocalDateTime.parse(timeStr, format.formatter);
        }
    
        // 01. java.util.Date --> java.time.LocalDateTime
        public static LocalDateTime dateToLocalDateTime(Date date) {
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            return LocalDateTime.ofInstant(instant, zone);
        }
    
    
        // 02. java.util.Date --> java.time.LocalDate
        public static LocalDate dateToLocalDate(Date date) {
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
            return localDateTime.toLocalDate();
        }
    
        // 03. java.util.Date --> java.time.LocalTime
        public static LocalTime dateToLocalTime(Date date) {
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
            return localDateTime.toLocalTime();
        }
    
    
        // 04. java.time.LocalDateTime --> java.util.Date
        public static Date localDateTimeToDate(LocalDateTime localDateTime) {
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zone).toInstant();
            return Date.from(instant);
        }
    
    
        // 05. java.time.LocalDate --> java.util.Date
        public static Date localDateToDate(LocalDate localDate) {
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
            return Date.from(instant);
        }
    
        // 06. java.time.LocalTime --> java.util.Date
        public static Date LocalTimeToDate(LocalDate localDate, LocalTime localTime) {
            LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zone).toInstant();
            return Date.from(instant);
        }
    
        /**
         * 时间转 String
         *
         * @param time
         * @return
         */
        public static String date2String(LocalDateTime time) {
            return DEFAULT_DATETIME_FORMATTER.format(time);
        }
    
        /**
         * 时间转 String
         *
         * @param time
         * @param format 时间格式
         * @return
         */
        public static String date2String(LocalDateTime time, TimeFormat format) {
            return format.formatter.format(time);
        }
    
    
        /**
         * 时间格式
         */
        public enum TimeFormat {
    
            /**
             * 短时间格式
             */
            SHORT_DATE_PATTERN_CHINA("yyyy年MM月dd日"),
            SHORT_DATE_PATTERN_LINE("yyyy-MM-dd"),
            SHORT_DATE_PATTERN_SLASH("yyyy/MM/dd"),
            SHORT_DATE_PATTERN_DOUBLE_SLASH("yyyy\\MM\\dd"),
            SHORT_DATE_PATTERN_NONE("yyyyMMdd"),
    
            /**
             * 长时间格式
             */
            LONG_DATE_BEGIN_PATTERN_LINE("yyyy-MM-dd 00:00:00"),
            LONG_DATE_END_PATTERN_LINE("yyyy-MM-dd 23:59:59"),
            LONG_DATE_PATTERN_LINE("yyyy-MM-dd HH:mm:ss"),
            LONG_DATE_PATTERN_SLASH("yyyy/MM/dd HH:mm:ss"),
            LONG_DATE_PATTERN_DOUBLE_SLASH("yyyy\\MM\\dd HH:mm:ss"),
            LONG_DATE_PATTERN_NONE("yyyyMMdd HH:mm:ss"),
            LONG_DATE_PATTERN_ALL_NONE("yyyyMMddHHmmss"),
            LONG_DATE_PATTERN_CHINA("yyyy年MM月dd日 HH:mm:ss"),
            LONG_DATE_BEGIN_PATTERN_CHINA("yyyy年MM月dd日 00:00:00"),
    
            /**
             * 长时间格式 带毫秒
             */
            LONG_DATE_PATTERN_WITH_MILSEC_LINE("yyyy-MM-dd HH:mm:ss.SSS"),
            LONG_DATE_PATTERN_WITH_MILSEC_SLASH("yyyy/MM/dd HH:mm:ss.SSS"),
            LONG_DATE_PATTERN_WITH_MILSEC_DOUBLE_SLASH("yyyy\\MM\\dd HH:mm:ss.SSS"),
            LONG_DATE_PATTERN_WITH_MILSEC_NONE("yyyyMMdd HH:mm:ss.SSS");
    
            public transient DateTimeFormatter formatter;
    
            TimeFormat(String pattern) {
                formatter = DateTimeFormatter.ofPattern(pattern);
            }
        }
    
        /**
         * 获取指定date的后一天作为保单生效时间
         * @param date 一般是投保日
         * @return
         */
        @SneakyThrows
        public static Date getNextDateAsEffectiveTime(Date date){
            return org.apache.commons.lang3.time.DateUtils.truncate(org.apache.commons.lang3.time.DateUtils.addDays(date, 1), Calendar.DATE);
        }
    
    
        /**
         * 获取下一年的日期作为保单失效时间
         * @param date 一般是保单生效日 20190528000000
         * @return 20200527235959
         */
        @SneakyThrows
        public static Date getNextYearAsExpiredTime(Date date){
            date = addYears(date, 1);
            date = truncate(date, Calendar.DATE);
            return addSeconds(date, -1);
        }
    
        /**
         * 获取指定date的作为保单生效时间
         * @param date 格式化date的时分秒为00:00:00
         * @return
         */
        @SneakyThrows
        public static Date getEffectiveTimeByDate(Date date){
            return org.apache.commons.lang3.time.DateUtils.truncate(date, Calendar.DATE);
        }
    
        /**
         * 判断当前时间是否处于两个时间中间,不判断beginTime和endTime逻辑大小
         *
         * @param beginTime 开始时间
         * @param endTime   结束时间
         * @return true or false
         */
        public static boolean isBetween(Date beginTime, Date endTime) {
            Date now = new Date();
            if (now.after(beginTime) && now.before(endTime)) {
                return true;
            }
            return false;
        }
    }

     

  • 相关阅读:
    队列01--[队列&双端队列&循环队列&双端循环队列]
    LeetCode--[栈]--不定时更新
    栈01--[栈接口设计&&栈应用]
    初等数论初步
    成外国庆集训小记
    图论算法初步
    Are Lights Still On?
    二分答案和三分入门
    SCOI2010 传送带
    微信小程序 菜鸟笔记
  • 原文地址:https://www.cnblogs.com/antonyhubei/p/16112938.html
Copyright © 2020-2023  润新知