最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java生成訂單號或唯一id的高并發(fā)方案(4種方法)

 更新時間:2024年01月22日 15:54:06   作者:吳名氏.  
本文主要介紹了Java生成訂單號或唯一id的高并發(fā)方案,包括4種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、直接使用uuid

public static String getUUID() {
        String replaceUUID = UUID.randomUUID().toString().replace("-", "");
        return replaceUUID;
    }

但由于生成的數(shù)據(jù)沒有規(guī)律性,并且太長;

測試:循環(huán)1000w次

測試代碼:

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        Set set=new HashSet<>();
        for(int i=0;i<10000000;i++){
            String uuid = getUUID();
            System.out.println("uuid---"+i+"======="+uuid);
            set.add(uuid);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("set.size():"+set.size());
        System.out.println("endTime-startTime:"+(endTime-startTime));
    }

控制臺提示:

2、用時間(精確到毫秒)+隨機(jī)數(shù)

         //時間(精確到毫秒)
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String localDate = LocalDateTime.now().format(ofPattern);
        //隨機(jī)數(shù)
        String randomNumeric = RandomStringUtils.randomNumeric(8);

for循環(huán)1000w次,發(fā)現(xiàn)重復(fù)數(shù)據(jù)太多。因此光靠隨機(jī)數(shù)并不可靠。

3、使用 時間(精確到毫秒)+隨機(jī)數(shù)+用戶id(業(yè)務(wù)id)

注意:如果是類似用戶id,項目當(dāng)中集成了權(quán)限框架,使用工具類獲取即可,就不用傳參了

   /**
     * 生成訂單號(25位):時間(精確到毫秒)+3位隨機(jī)數(shù)+5位用戶id
     */
    public static synchronized  String getOrderNum(Long userId) {
        //時間(精確到毫秒)
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String localDate = LocalDateTime.now().format(ofPattern);
        //3位隨機(jī)數(shù)
        String randomNumeric = RandomStringUtils.randomNumeric(3);
        //5位用戶id
        int subStrLength = 5;
        String sUserId = userId.toString();
        int length = sUserId.length();
        String str;
        if (length >= subStrLength) {
            str = sUserId.substring(length - subStrLength, length);
        } else {
            str = String.format("%0" + subStrLength + "d", userId);
        }
        String orderNum = localDate + randomNumeric + str;
        log.info("訂單號:{}", orderNum);
        return orderNum;
    }

在2的基礎(chǔ)上改造,加入用戶的id等其他的業(yè)務(wù)id。

4.Java實現(xiàn)Snowflake算法的方案(高并發(fā)下,推薦使用這個)

package com.lucifer.order.util.idgenerate;
 
/**
 * Twitter_Snowflake<br>
 * SnowFlake的結(jié)構(gòu)如下(每部分用-分開):<br>
 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
 * 1位標(biāo)識,由于long基本類型在Java中是帶符號的,最高位是符號位,正數(shù)是0,負(fù)數(shù)是1,所以id一般是正數(shù),最高位是0<br>
 * 41位時間截(毫秒級),注意,41位時間截不是存儲當(dāng)前時間的時間截,而是存儲時間截的差值(當(dāng)前時間截 - 開始時間截)
 * 得到的值),這里的的開始時間截,一般是我們的id生成器開始使用的時間,由我們程序來指定的(如下下面程序IdWorker類的startTime屬性)。41位的時間截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
 * 10位的數(shù)據(jù)機(jī)器位,可以部署在1024個節(jié)點,包括5位datacenterId和5位workerId<br>
 * 12位序列,毫秒內(nèi)的計數(shù),12位的計數(shù)順序號支持每個節(jié)點每毫秒(同一機(jī)器,同一時間截)產(chǎn)生4096個ID序號<br>
 * 加起來剛好64位,為一個Long型。<br>
 * SnowFlake的優(yōu)點是,整體上按照時間自增排序,并且整個分布式系統(tǒng)內(nèi)不會產(chǎn)生ID碰撞(由數(shù)據(jù)中心ID和機(jī)器ID作區(qū)分),并且效率較高,經(jīng)測試,SnowFlake每秒能夠產(chǎn)生26萬ID左右。
 *
 * @author Lucifer
 */
public class SnowFlake {
 
    // ==============================Fields===========================================
    /**
     * 開始時間截 (2018-07-03)
     */
 
    private final long twepoch = 1530607760000L;
 
    /**
     * 機(jī)器id所占的位數(shù)
     */
    private final long workerIdBits = 5L;
 
    /**
     * 數(shù)據(jù)標(biāo)識id所占的位數(shù)
     */
    private final long datacenterIdBits = 5L;
 
    /**
     * 支持的最大機(jī)器id,結(jié)果是31 (這個移位算法可以很快的計算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù))
     */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
 
    /**
     * 支持的最大數(shù)據(jù)標(biāo)識id,結(jié)果是31
     */
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
 
    /**
     * 序列在id中占的位數(shù)
     */
    private final long sequenceBits = 12L;
 
    /**
     * 機(jī)器ID向左移12位
     */
    private final long workerIdShift = sequenceBits;
 
    /**
     * 數(shù)據(jù)標(biāo)識id向左移17位(12+5)
     */
    private final long datacenterIdShift = sequenceBits + workerIdBits;
 
    /**
     * 時間截向左移22位(5+5+12)
     */
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
 
    /**
     * 生成序列的掩碼,這里為4095 (0b111111111111=0xfff=4095)
     */
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
 
    /**
     * 工作機(jī)器ID(0~31)
     */
    private long workerId;
 
    /**
     * 數(shù)據(jù)中心ID(0~31)
     */
    private long datacenterId;
 
    /**
     * 毫秒內(nèi)序列(0~4095)
     */
    private long sequence = 0L;
 
    /**
     * 上次生成ID的時間截
     */
    private long lastTimestamp = -1L;
 
    //==============================Constructors=====================================
 
    /**
     * 構(gòu)造函數(shù)
     *
     * @param workerId     工作ID (0~31)
     * @param datacenterId 數(shù)據(jù)中心ID (0~31)
     */
    public SnowFlake(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
 
    // ==============================Methods==========================================
 
    /**
     * 獲得下一個ID (該方法是線程安全的)
     *
     * @return SnowflakeId
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
 
        //如果當(dāng)前時間小于上一次ID生成的時間戳,說明系統(tǒng)時鐘回退過這個時候應(yīng)當(dāng)拋出異常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
 
        //如果是同一時間生成的,則進(jìn)行毫秒內(nèi)序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            //毫秒內(nèi)序列溢出
            if (sequence == 0) {
                //阻塞到下一個毫秒,獲得新的時間戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        }
        //時間戳改變,毫秒內(nèi)序列重置
        else {
            sequence = 0L;
        }
 
        //上次生成ID的時間截
        lastTimestamp = timestamp;
 
        //移位并通過或運算拼到一起組成64位的ID
        return (((timestamp - twepoch) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift)
                | sequence);
    }
 
    /**
     * 阻塞到下一個毫秒,直到獲得新的時間戳
     *
     * @param lastTimestamp 上次生成ID的時間截
     * @return 當(dāng)前時間戳
     */
    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }
 
    /**
     * 返回以毫秒為單位的當(dāng)前時間
     *
     * @return 當(dāng)前時間(毫秒)
     */
    protected long timeGen() {
        return System.currentTimeMillis();
    }
 
    //==============================Test=============================================
 
    /**
     * 測試
     */
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        SnowFlake idWorker = new SnowFlake(0, 0);
        Set set = new HashSet();
        for (int i = 0; i < 10000000; i++) {
            long id = idWorker.nextId();
            set.add(id);
            System.out.println("id----"+i+":"+id);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("set.size():" + set.size());
        System.out.println("endTime-startTime:" + (endTime - startTime));
    }
}

也可以在雪花算法生成的id的基礎(chǔ)上拼接日期,不過性能有所損耗。 

 public static String timestampConversionDate(String param) {
        Instant timestamp = Instant.ofEpochMilli(new Long(param));
        System.out.println("timestamp:"+param);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault());
        String format = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        return format;
    }

測試1:

循環(huán)1000w次,發(fā)現(xiàn)并無重復(fù)

測試2:100個線程,每個線程負(fù)責(zé)生成10w個id

//多線程測試
public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        CountDownLatch countDownLatch=new CountDownLatch(10000000);
        final SnowFlake idWorker = new SnowFlake(0, 0);
        Set set = Collections.synchronizedSet(new HashSet());
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(() -> {
                for (int i1 = 0; i1 < 100000; i1++) {
                    long id = idWorker.nextId();
                    System.out.println("id:"+id);
                    set.add(id);
                    countDownLatch.countDown();
                }
            });
            thread.start();
        }
        countDownLatch.await();
        long endTime = System.currentTimeMillis();
        System.out.println("set.size():" + set.size());
        System.out.println("endTime-startTime:" + (endTime - startTime));
    }

到此這篇關(guān)于Java生成訂單號或唯一id的高并發(fā)方案(4種方法)的文章就介紹到這了,更多相關(guān)Java生成訂單號或唯一id內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java定時器通信協(xié)議管理模塊Timer詳解

    Java定時器通信協(xié)議管理模塊Timer詳解

    這篇文章主要介紹了Java定時器通信協(xié)議管理模塊Timer,?Timer一般指定時器(通信協(xié)議管理模塊)人類最早使用的定時工具是沙漏或水漏,但在鐘表誕生發(fā)展成熟之后,人們開始嘗試使用這種全新的計時工具來改進(jìn)定時器,達(dá)到準(zhǔn)確控制時間的目的
    2022-08-08
  • Hibernate映射之基本類映射和對象關(guān)系映射詳解

    Hibernate映射之基本類映射和對象關(guān)系映射詳解

    這篇文章主要介紹了Hibernate映射之基本類映射和對象關(guān)系映射詳解,非常具有實用價值,需要的朋友可以參考下
    2017-05-05
  • Springboot+QueryDsl實現(xiàn)融合數(shù)據(jù)查詢

    Springboot+QueryDsl實現(xiàn)融合數(shù)據(jù)查詢

    這篇文章主要將介紹的是 Springboot 使用 QueryDsl 實現(xiàn)融合數(shù)據(jù)查詢,文中有詳細(xì)的代碼講解,對 SpringBoot?Querydsl?查詢操作感興趣的朋友一起看看吧
    2023-08-08
  • SpringBoot解決跨域的5種方式小結(jié)

    SpringBoot解決跨域的5種方式小結(jié)

    在項目開發(fā)中,時常會遇到跨域問題,本文主要介紹了五種解決跨域的方法,使用最多的是第三種,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • Spring?Security?過濾器注冊脈絡(luò)梳理

    Spring?Security?過濾器注冊脈絡(luò)梳理

    這篇文章主要介紹了Spring?Security過濾器注冊脈絡(luò)梳理,Spring?Security在Servlet的過濾鏈中注冊了一個過濾器FilterChainProxy,它會把請求代理到Spring?Security自己維護(hù)的多個過濾鏈,每個過濾鏈會匹配一些URL,如果匹配則執(zhí)行對應(yīng)的過濾器
    2022-08-08
  • SpringBoot底層注解詳解

    SpringBoot底層注解詳解

    這篇文章主要介紹了SpringBoot底層注解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-05-05
  • MyBatis映射器模塊最佳實踐

    MyBatis映射器模塊最佳實踐

    MyBatis是一種優(yōu)秀的持久層框架,它通過接口+配置的方式實現(xiàn)了數(shù)據(jù)庫操作的優(yōu)雅,映射器模塊(MapperInterface)是用戶與MyBatis交互的主要入口,本文介紹MyBatis映射器模塊最佳實踐,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • Java根據(jù)實體生成SQL數(shù)據(jù)庫表的示例代碼

    Java根據(jù)實體生成SQL數(shù)據(jù)庫表的示例代碼

    這篇文章主要來和大家分享一個Java實現(xiàn)根據(jù)實體生成SQL數(shù)據(jù)庫表的代碼,文中的實現(xiàn)代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-07-07
  • java中random的用法小結(jié)

    java中random的用法小結(jié)

    這篇文章主要介紹了java中random的用法詳解,主要包括java.lang.Math.random()方法的用法及java.util.Random類用法,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Windows上安裝不同版本JDK并切換使用的詳細(xì)步驟

    Windows上安裝不同版本JDK并切換使用的詳細(xì)步驟

    在Windows操作系統(tǒng)中,管理和切換Java Development Kit (JDK) 的版本是一項常見的任務(wù),尤其是在開發(fā)環(huán)境中,這篇文章主要介紹了Windows上安裝不同版本JDK并切換使用的相關(guān)資料,需要的朋友可以參考下
    2025-09-09

最新評論

德庆县| 上饶市| 津市市| 侯马市| 信阳市| 永福县| 清新县| 南澳县| 苍溪县| 临高县| 微山县| 磐石市| 云林县| 天柱县| 平度市| 宁晋县| 镇原县| 云南省| 新干县| 长丰县| 景谷| 会东县| 建湖县| 昂仁县| 睢宁县| 金堂县| 凉城县| 南丰县| 玉溪市| 时尚| 绩溪县| 峨眉山市| 永定县| 青川县| 钟山县| 丰镇市| 友谊县| 泗水县| 淮滨县| 江陵县| 平邑县|