欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Redis實(shí)現(xiàn)分布式單號(hào)及分布式ID(自定義規(guī)則生成)

 更新時(shí)間:2021年09月22日 10:39:55   作者:程序員小強(qiáng)  
一些業(yè)務(wù)背景下,業(yè)務(wù)要求單號(hào)需要有區(qū)分不同的前綴,那么在分布式的架構(gòu)下如何自定義單號(hào)而且還能保證唯一呢?本文就來(lái)詳細(xì)的介紹一下

背景

一些業(yè)務(wù)背景下,業(yè)務(wù)要求單號(hào)需要有區(qū)分不同的前綴,那么在分布式的架構(gòu)下如何自定義單號(hào)而且還能保證唯一呢?

注:分布式ID也可以此方式

Redis實(shí)現(xiàn)方式

Redis的所有命令操作都是單線程的,本身提供像 incr 和 increby 這樣的自增原子命令,所以能保證生成的 ID 肯定是唯一有序的。

優(yōu)點(diǎn):不依賴(lài)于數(shù)據(jù)庫(kù),靈活方便,且性能優(yōu)于數(shù)據(jù)庫(kù);數(shù)字ID天然排序,對(duì)分頁(yè)或者需要排序的結(jié)果很有幫助。

缺點(diǎn):如果系統(tǒng)中沒(méi)有Redis,還需要引入新的組件,增加系統(tǒng)復(fù)雜度;需要編碼和配置的工作量比較大。

考慮到單節(jié)點(diǎn)的性能瓶頸,可以使用 Redis 集群來(lái)獲取更高的吞吐量。
使用 Redis 集群也可以方式單點(diǎn)故障的問(wèn)題。

代碼實(shí)例

創(chuàng)建常量類(lèi)

/**
 * 單號(hào)生成常量
 *
 * @author mq
 */
public class FormNoConstants {
    /**
     * 單號(hào)流水號(hào)緩存Key前綴
     */
    public static final String SERIAL_CACHE_PREFIX = "FORM_NO_CACHE_";

    /**
     * 單號(hào)流水號(hào)yyMMdd前綴
     */
    public static final String SERIAL_YYMMDD_PREFIX = "yyMMdd";

    /**
     * 單號(hào)流水號(hào)yyyyMMdd前綴
     */
    public static final String SERIAL_YYYYMMDD_PREFIX = "yyyyMMdd";
    
    /**
     * 默認(rèn)緩存天數(shù)
     */
    public static final int DEFAULT_CACHE_DAYS = 7;
}

單號(hào)生成枚舉

注:為了方便擴(kuò)展,方便復(fù)用,使用枚舉方式,可以自定義枚舉值來(lái)生成不同的單號(hào)

/**
 * 單號(hào)生成類(lèi)型枚舉
 *
 * @author mq
 * 注:隨機(jī)號(hào)位于流水號(hào)之后,流水號(hào)使用redis計(jì)數(shù)據(jù),每天都是一個(gè)新的key,長(zhǎng)度不足時(shí)則自動(dòng)補(bǔ)0
 * <p>
 * 生成規(guī)則 =固定前綴+當(dāng)天日期串+流水號(hào)(redis自增,不足長(zhǎng)度則補(bǔ)0)+隨機(jī)數(shù)
 */
public enum FormNoTypeEnum {

    /**
     * 應(yīng)付單單號(hào):
     * 固定前綴:YF
     * 時(shí)間格式:yyyyMMdd
     * 流水號(hào)長(zhǎng)度:7(當(dāng)單日單據(jù)較多時(shí)可根據(jù)業(yè)務(wù)適當(dāng)增加流水號(hào)長(zhǎng)度)
     * 隨機(jī)數(shù)長(zhǎng)度:3
     * 總長(zhǎng)度:20
     */
    YF_ORDER("YF", FormNoConstants.SERIAL_YYYYMMDD_PREFIX, 7, 3, 20),

    /**
     * 付款單單號(hào):
     * 固定前綴:FK
     * 時(shí)間格式:yyyyMMdd
     * 流水號(hào)長(zhǎng)度:7
     * 隨機(jī)數(shù)長(zhǎng)度:3
     * 總長(zhǎng)度:20
     */
    FK_ORDER("FK", FormNoConstants.SERIAL_YYYYMMDD_PREFIX, 7, 3, 20),

    /**
     * 測(cè)試單單號(hào):
     * 固定前綴:""
     * 時(shí)間格式:yyyyMMdd
     * 流水號(hào)長(zhǎng)度:10
     * 隨機(jī)數(shù)長(zhǎng)度:0
     * 總長(zhǎng)度:20
     */
    TEST_ORDER("te", FormNoConstants.SERIAL_YYYYMMDD_PREFIX, 10, 0, 20),
    ;

    /**
     * 單號(hào)前綴
     * 為空時(shí)填""
     */
    private String prefix;

    /**
     * 時(shí)間格式表達(dá)式
     * 例如:yyyyMMdd
     */
    private String datePattern;

    /**
     * 流水號(hào)長(zhǎng)度
     */
    private Integer serialLength;
    /**
     * 隨機(jī)數(shù)長(zhǎng)度
     */
    private Integer randomLength;

    /**
     * 總長(zhǎng)度
     */
    private Integer totalLength;


    FormNoTypeEnum(String prefix, String datePattern, Integer serialLength, Integer randomLength, Integer totalLength) {
        this.prefix = prefix;
        this.datePattern = datePattern;
        this.serialLength = serialLength;
        this.randomLength = randomLength;
        this.totalLength = totalLength;
    }
    //省略 get 方法
}

單號(hào)生成工具類(lèi)

/**
 * 單號(hào)生成工具類(lèi)
 *
 * @author mq
 */
public class FormNoSerialUtil {

    /**
     * 生成單號(hào)前綴
     */
    public static String getFormNoPrefix(FormNoTypeEnum formNoTypeEnum) {
        //格式化時(shí)間
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formNoTypeEnum.getDatePattern());
        StringBuffer sb = new StringBuffer();
        sb.append(formNoTypeEnum.getPrefix());
        sb.append(formatter.format(LocalDateTime.now()));
        return sb.toString();
    }
    
    /**
     * 構(gòu)建流水號(hào)緩存Key
     *
     * @param serialPrefix 流水號(hào)前綴
     * @return 流水號(hào)緩存Key
     */
    public static String getCacheKey(String serialPrefix) {
        return FormNoConstants.SERIAL_CACHE_PREFIX.concat(serialPrefix);
    }
    
    /**
     * 補(bǔ)全流水號(hào)
     *
     * @param serialPrefix      單號(hào)前綴
     * @param incrementalSerial 當(dāng)天自增流水號(hào)
     * @author mengqiang
     * @date 2019/1/1
     */
    public static String completionSerial(String serialPrefix, Long incrementalSerial,
                                          FormNoTypeEnum formNoTypeEnum) {
        StringBuffer sb = new StringBuffer(serialPrefix);

        //需要補(bǔ)0的長(zhǎng)度=流水號(hào)長(zhǎng)度 -當(dāng)日自增計(jì)數(shù)長(zhǎng)度
        int length = formNoTypeEnum.getSerialLength() - String.valueOf(incrementalSerial).length();
        //補(bǔ)零
        for (int i = 0; i < length; i++) {
            sb.append("0");
        }
        //redis當(dāng)日自增數(shù)
        sb.append(incrementalSerial);
        return sb.toString();
    }


    /**
     * 補(bǔ)全隨機(jī)數(shù)
     *
     * @param serialWithPrefix 當(dāng)前單號(hào)
     * @param formNoTypeEnum   單號(hào)生成枚舉
     * @author mengqiang
     * @date 2019/1/1
     */
    public static String completionRandom(String serialWithPrefix, FormNoTypeEnum formNoTypeEnum) {
        StringBuffer sb = new StringBuffer(serialWithPrefix);
        //隨機(jī)數(shù)長(zhǎng)度
        int length = formNoTypeEnum.getRandomLength();
        if (length > 0) {
            Random random = new Random();
            for (int i = 0; i < length; i++) {
                //十以內(nèi)隨機(jī)數(shù)補(bǔ)全
                sb.append(random.nextInt(10));
            }
        }
        return sb.toString();
    }
}

單號(hào)生成接口

/**
 * 單號(hào)生成接口
 *
 * @author mq
 */
public interface FormNoGenerateService {

    /**
     * 根據(jù)單據(jù)編號(hào)類(lèi)型 生成單據(jù)編號(hào)
     *
     * @param formNoTypeEnum 單據(jù)編號(hào)類(lèi)型
     * @author mengqiang
     * @date 2019/1/1
     */
    String generateFormNo(FormNoTypeEnum formNoTypeEnum);
}

單號(hào)生成接口實(shí)現(xiàn)

/**
 * 單號(hào)生成接口實(shí)現(xiàn)
 *
 * @author mengqiang
 * @version FormNoGenerateServiceImpl.java, v 1.0 2019-01-01 18:10
 */
@Service
public class FormNoGenerateServiceImpl implements FormNoGenerateService {
    /**
     * redis 服務(wù)
     * demo 項(xiàng)目沒(méi)有加redis相關(guān),若有需要請(qǐng)參考,redis的博客
     */
    @Autowired
    private RedisCache redisCache;
    /**
     * 根據(jù)單據(jù)編號(hào)類(lèi)型 生成單據(jù)編號(hào)
     *
     * @param formNoTypeEnum 單據(jù)編號(hào)類(lèi)型
     * @author mengqiang
     * @date 2019/1/1
     */
    @Override
    public String generateFormNo(FormNoTypeEnum formNoTypeEnum) {
        //獲得單號(hào)前綴
        //格式 固定前綴 +時(shí)間前綴 示例 :YF20190101
        String formNoPrefix = FormNoSerialUtil.getFormNoPrefix(formNoTypeEnum);
        //獲得緩存key
        String cacheKey = FormNoSerialUtil.getCacheKey(formNoPrefix);
        //獲得當(dāng)日自增數(shù)
        Long incrementalSerial = redisCache.incr(cacheKey);
        //設(shè)置失效時(shí)間 7天
        redisCache.expire(cacheKey, FormNoConstants.DEFAULT_CACHE_DAYS, TimeUnit.DAYS);
        //組合單號(hào)并補(bǔ)全流水號(hào)
        String serialWithPrefix = FormNoSerialUtil
                .completionSerial(formNoPrefix, incrementalSerial, formNoTypeEnum);
        //補(bǔ)全隨機(jī)數(shù)
        return FormNoSerialUtil.completionRandom(serialWithPrefix, formNoTypeEnum);
    }
}

使用測(cè)試

在這里插入圖片描述

redis截圖

在這里插入圖片描述

總結(jié)

以上還不是最優(yōu)雅的方式,最好是能做成jar包方式,做成通用的服務(wù)

到此這篇關(guān)于基于Redis實(shí)現(xiàn)分布式單號(hào)及分布式ID(自定義規(guī)則生成)的文章就介紹到這了,更多相關(guān)基于Redis實(shí)現(xiàn)分布式單號(hào)及分布式ID(自定義規(guī)則生成)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • redis客戶端連接錯(cuò)誤 NOAUTH Authentication required

    redis客戶端連接錯(cuò)誤 NOAUTH Authentication required

    本文主要介紹了redis客戶端連接錯(cuò)誤 NOAUTH Authentication required,詳細(xì)的介紹了解決方法,感興趣的可以了解一下
    2021-07-07
  • Redis 哨兵機(jī)制及配置實(shí)現(xiàn)

    Redis 哨兵機(jī)制及配置實(shí)現(xiàn)

    本文主要介紹了Redis 哨兵機(jī)制及配置實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Redis執(zhí)行Lua腳本的好處與示例代碼

    Redis執(zhí)行Lua腳本的好處與示例代碼

    Redis在2.6推出了腳本功能,允許開(kāi)發(fā)者使用Lua語(yǔ)言編寫(xiě)腳本傳到Redis中執(zhí)行。下面這篇文章主要給大家介紹了關(guān)于Redis執(zhí)行Lua腳本的好處與示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-10-10
  • RedisAPI原子性操作及原理解析

    RedisAPI原子性操作及原理解析

    這篇文章主要介紹了RedisAPI原子性操作及原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 淺談redission鎖的默認(rèn)失效時(shí)間

    淺談redission鎖的默認(rèn)失效時(shí)間

    Redisson是一個(gè)基于Redis的Java駐留庫(kù),提供了許多分布式對(duì)象和服務(wù),包括分布式鎖,本文主要介紹了淺談redission鎖的默認(rèn)失效時(shí)間, 具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • Redis高級(jí)數(shù)據(jù)類(lèi)型Hyperloglog、Bitmap的使用

    Redis高級(jí)數(shù)據(jù)類(lèi)型Hyperloglog、Bitmap的使用

    很多小伙伴在面試中都會(huì)被問(wèn)道 Redis的常用數(shù)據(jù)結(jié)構(gòu)有哪些?可能很大一部分回答都是 string、hash、list、set、zset,但其實(shí)還有Hyperloglog和Bitmap,本文就來(lái)介紹一下
    2021-05-05
  • Redis緩存工具封裝實(shí)現(xiàn)

    Redis緩存工具封裝實(shí)現(xiàn)

    本文主要介紹了Redis緩存工具封裝實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Redis實(shí)現(xiàn)分布式Session管理的機(jī)制詳解

    Redis實(shí)現(xiàn)分布式Session管理的機(jī)制詳解

    這篇文章主要介紹了Redis實(shí)現(xiàn)分布式Session管理的機(jī)制詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 詳解redis緩存與數(shù)據(jù)庫(kù)一致性問(wèn)題解決

    詳解redis緩存與數(shù)據(jù)庫(kù)一致性問(wèn)題解決

    這篇文章主要介紹了詳解redis緩存與數(shù)據(jù)庫(kù)一致性問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 詳解Redis單線程架構(gòu)的優(yōu)勢(shì)與不足

    詳解Redis單線程架構(gòu)的優(yōu)勢(shì)與不足

    很多人都遇到過(guò)這么一道面試題:Redis是單線程還是多線程?這個(gè)問(wèn)題既簡(jiǎn)單又復(fù)雜,說(shuō)他簡(jiǎn)單是因?yàn)榇蠖鄶?shù)人都知道Redis是單線程,說(shuō)復(fù)雜是因?yàn)檫@個(gè)答案其實(shí)并不準(zhǔn)確,本文就給大家講講Redis單線程架構(gòu)的優(yōu)勢(shì)與不足,需要的朋友可以參考下
    2024-02-02

最新評(píng)論