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

Java版雪花算法生成ID實用工具類完整實例

 更新時間:2026年04月14日 09:57:13   作者:兩點王爺  
雪花算法是一種分布式唯一ID生成算法,可以生成全局唯一的ID標識符,就像自然界中雪花一般沒有相同的雪花,這篇文章主要介紹了Java版雪花算法生成ID實用工具類的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

ID的生成一般可以是序列遞增、雪花算法、UUID等等

各個特點如下:

序列自增

‌? 優(yōu)點:

  1. 占用空間小‌:自增ID通常使用較小的數(shù)據(jù)類型(如INT),占用存儲空間較小。
  2. 性能好‌:自增ID是順序生成的,可以連續(xù)存儲在磁盤上,有利于提高插入操作的性能,減少碎片化。
  3. 易于排序和索引‌:自增ID可以快速排序和索引,有利于提高查詢效率。

‌? 缺點:

  1. 局部唯一性‌:在單數(shù)據(jù)庫實例中是唯一的,但在分布式系統(tǒng)中或在多個數(shù)據(jù)庫之間使用時需要額外的機制來確保全局唯一性(例如使用UUID或其他分布式ID生成策略)。
  2. 需要數(shù)據(jù)庫級別的唯一性檢查‌:每次插入前需要檢查是否已存在相同的ID,這會增加數(shù)據(jù)庫的負擔。
  3. 重用問題‌:如果在刪除記錄后不重新使用ID,會導(dǎo)致ID的浪費。雖然可以通過一些策略(如預(yù)留ID池)解決,但這增加了實現(xiàn)的復(fù)雜性。

雪花算法

雪花算法(Snowflake Algorithm)是由 Twitter 設(shè)計并開源的一種分布式唯一 ID 生成算法,用于在高并發(fā)、分布式環(huán)境下高效生成全局唯一、時間有序的 64 位整數(shù) ID(Long 類型)。其核心思想是將一個 64 位二進制數(shù)劃分為多個功能段,通過“時間戳 + 機器標識 + 序列號”組合生成 ID。

64 位雪花 ID 位分配圖解(標準版)

 0          41        51          63
┌────────────┬─────────┬───────────┐
│  timestamp │ dataCtr │  worker   │ sequence
│  (41 bits) │ (5 bits)│  (5 bits) │ (12 bits)
└────────────┴─────────┴───────────┘
         ↑
     64-bit signed long (最高位為符號位,始終為 0 → 實際可用 63 位)
字段長度取值范圍說明
timestamp41 位0 ~ 2?¹−1 ms ≈ 69.7 年自 EPOCH 起的毫秒差;決定 ID 時間序和生命周期
datacenterId5 位0 ~ 31標識數(shù)據(jù)中心(如:北京=1、上海=2)
workerId5 位0 ~ 31標識該中心內(nèi)的具體機器(進程)
sequence12 位0 ~ 4095同一毫秒內(nèi)自增序號;支持單機峰值 4096 ID/ms

?? 示例 ID 解析(十進制)1829347561234567168
→ 轉(zhuǎn)二進制后截取對應(yīng)字段,即可還原生成時間、機房、機器與序號。

優(yōu)點

維度說明
全局唯一性基于時間戳(毫秒級)+ 數(shù)據(jù)中心 ID + 機器 ID + 序列號,理論上在集群規(guī)模合理、時鐘不回撥前提下,ID 絕對唯一。
高性能 & 低延遲完全本地內(nèi)存運算,無網(wǎng)絡(luò)/數(shù)據(jù)庫依賴,單機 QPS 可達數(shù)萬甚至數(shù)十萬。
時間有序性(近似單調(diào)遞增)高位為時間戳,生成的 ID 隨時間大致遞增,有利于數(shù)據(jù)庫(如 MySQL)索引優(yōu)化(減少頁分裂)、范圍查詢等。
結(jié)構(gòu)化 & 可解析ID 可直接解碼出生成時間、所屬節(jié)點等信息,便于問題追蹤與運維分析。
輕量易集成無外部依賴,主流語言均有成熟實現(xiàn)(Java/Go/Python 等),易于嵌入微服務(wù)架構(gòu)。

缺點與局限性

維度說明
強依賴系統(tǒng)時鐘(時鐘回撥問題)若服務(wù)器時間發(fā)生回撥(如 NTP 校正、手動修改),可能導(dǎo)致 ID 重復(fù)或阻塞(取決于實現(xiàn)策略)。需配合時鐘監(jiān)控、容忍策略(如等待、拋異常、降級為隨機 ID)等機制緩解。
ID 位數(shù)固定,存在理論上限64 位中:41 位時間戳(約 69 年)、10 位機器標識(最多 1024 節(jié)點)、12 位序列號(每毫秒最多 4096 個 ID)。時間戳耗盡后需升級位分配(如擴展為 65+ 位,但破壞兼容性)。
機器 ID 需人工/中心化分配datacenterId 和 workerId 需全局唯一且預(yù)先配置,大規(guī)模動態(tài)擴縮容時管理成本上升(需結(jié)合 ZooKeeper、Etcd 或數(shù)據(jù)庫注冊中心解決)。
非密碼學(xué)安全ID 可被預(yù)測(尤其已知部分參數(shù)和時間范圍時),不適用于需要防猜測、防枚舉的場景(如訂單號、優(yōu)惠券碼等)。
單機吞吐受限于序列號位寬每毫秒最多生成 2^12 = 4096 個 ID;若瞬時并發(fā)超限,會阻塞等待下一毫秒(導(dǎo)致少量延遲毛刺)。

?? 補充說明(常見變種優(yōu)化)

  • 百度 UidGenerator:基于雪花改進,引入 RingBuffer 緩存 + 時間自增補償,緩解時鐘回撥與序列號瓶頸。
  • 美團 Leaf(Segment 模式 / Snowflake 模式):提供兩種模式,Snowflake 模式即增強版雪花,增加動態(tài) workerId 分配與健康檢測。
  • Twitter 官方已棄用:Twitter 后期轉(zhuǎn)向更靈活的混合方案(如基于 Kafka 的日志序號 + 時間戳),但雪花因其簡潔性仍被業(yè)界廣泛采用。

??  ID 生成方案對比表(Snowflake vs 其他主流方案)

維度SnowflakeUUID v4DB 自增主鍵Redis INCRLeaf-Segment(美團)
唯一性全局唯一(依賴配置+時鐘)全局唯一(概率極低重復(fù))單庫唯一,分布式需分庫分表/號段單 Redis 實例唯一,集群需協(xié)調(diào)全局唯一(號段預(yù)分配+雙 Buffer)
有序性? 近似時間有序(利于索引)? 完全無序(字符串,B+樹效率低)? 嚴格遞增? 嚴格遞增? 邏輯有序(號段內(nèi)有序)
性能? 極高(純內(nèi)存,μs 級)? 高(本地生成)? 依賴 DB 寫入(ms 級,有鎖)? 高(但依賴 Redis RTT)? 高(號段緩存,批量獲?。?/td>
可用性? 無外部依賴? 無依賴? DB 故障即不可用? Redis 故障即不可用?? 依賴 MySQL(號段管理)或 ZooKeeper
ID 長度/類型64 位整數(shù)(緊湊、易排序)128 位字符串(32 字符,存儲/索引開銷大)64 位整數(shù)64 位整數(shù)64 位整數(shù)
可讀性/可解析性? 可解析出時間、節(jié)點信息? 完全隨機,無業(yè)務(wù)含義? 僅序號,無時間/節(jié)點信息? 僅序號?? 可解析時間,但節(jié)點信息弱化
擴展性?? 機器 ID 需預(yù)分配,動態(tài)擴容較重? 天然無狀態(tài),無限擴展? 分庫分表復(fù)雜,全局有序難保證?? Redis 集群需路由一致性? 支持動態(tài)擴容(號段自動分配)
適用場景推薦:訂單 ID、消息 ID、日志 traceId 等高并發(fā)有序需求適合:臨時 token、文件名、非索引場景適合:單體應(yīng)用、低并發(fā)后臺系統(tǒng)適合:簡單計數(shù)、限流等非核心 ID推薦:大型電商/金融系統(tǒng)(兼顧性能、容災(zāi)、擴展)

?? 選型建議

  • 初創(chuàng)/中小系統(tǒng) → 優(yōu)先 Snowflake(簡單可靠);
  • 對可用性要求極高 → Leaf-Segment(MySQL 故障仍可發(fā)號數(shù)小時);
  • 禁止 ID 泄露業(yè)務(wù)規(guī)模 → 避免 Snowflake/自增,改用加密 UUID 或混淆 ID(如 Base62 編碼 + 鹽值哈希)。

雪花算法和UUID的核心區(qū)別在于:雪花算法生成的是‌具有時間有序性的64位整數(shù)‌,而UUID生成的是‌通常無序的128位標識符(常以字符串形式表示)‌,這導(dǎo)致了它們在數(shù)據(jù)庫性能、存儲效率以及適用場景上的顯著差異。

實用工具類如下:

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * 雪花ID生成器
 *
 */
public class SnowflakeIdGenerator {
    // ==================== 常量定義 ====================
    private static final long EPOCH = 1609459200000L; // 自定義起始時間:2021-01-01 00:00:00 UTC(毫秒)
    private static final int DATA_CENTER_ID_BITS = 5;
    private static final int WORKER_ID_BITS = 5;
    private static final int SEQUENCE_BITS = 12;
    private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);   // 31
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);               // 31
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);                 // 4095
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;                        // 12
    private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;  // 17
    private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS; // 22
    // ==================== 運行時變量 ====================
    private final long dataCenterId;
    private final long workerId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;
    // ==================== 構(gòu)造函數(shù) ====================
    public SnowflakeIdGenerator(long dataCenterId, long workerId) {
        if (dataCenterId < 0 || dataCenterId > MAX_DATA_CENTER_ID) {
            throw new IllegalArgumentException("dataCenterId must be in [0," + MAX_DATA_CENTER_ID + "]");
        }
        if (workerId < 0 || workerId > MAX_WORKER_ID) {
            throw new IllegalArgumentException("workerId must be in [0," + MAX_WORKER_ID + "]");
        }
        this.dataCenterId = dataCenterId;
        this.workerId = workerId;
    }
    // ==================== 核心方法 ====================
    public synchronized long nextId() {
        long timestamp = currentTimeMillis();
        // ?? 時鐘回撥處理:嚴格模式(拋異常) or 容忍模式(等待/告警)
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
                    lastTimestamp - timestamp));
        }
        if (lastTimestamp == timestamp) {
            // 同一毫秒內(nèi),序列號自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                // 當前毫秒序列已滿,阻塞至下一毫秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 新毫秒,序列號重置為 0
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        // 拼接 ID:(timestamp - epoch) << 22 | dataCenterId << 17 | workerId << 12 | sequence
        return ((timestamp - EPOCH) << TIMESTAMP_LEFT_SHIFT)
            | (dataCenterId << DATA_CENTER_ID_SHIFT)
            | (workerId << WORKER_ID_SHIFT)
            | sequence;
    }
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = currentTimeMillis();
        }
        return timestamp;
    }
    private long currentTimeMillis() {
        return System.currentTimeMillis();
    }
    // ==================== 輔助方法:解析 ID(可選) ====================
    public static class IdInfo {
        public final long timestamp;      // 時間戳(毫秒)
        public final long dataCenterId;   // 數(shù)據(jù)中心 ID
        public final long workerId;       // 工作節(jié)點 ID
        public final long sequence;       // 序列號
        public IdInfo(long timestamp, long dataCenterId, long workerId, long sequence) {
            this.timestamp = timestamp;
            this.dataCenterId = dataCenterId;
            this.workerId = workerId;
            this.sequence = sequence;
        }
        public IdInfo(long id) {
            this.timestamp = (id >> TIMESTAMP_LEFT_SHIFT) + EPOCH;
            this.dataCenterId = (id >> DATA_CENTER_ID_SHIFT) & MAX_DATA_CENTER_ID;
            this.workerId = (id >> WORKER_ID_SHIFT) & MAX_WORKER_ID;
            this.sequence = id & MAX_SEQUENCE;
        }
    }
    public static void main(String[] args) {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 2);
        List<Long> ids = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            long id = idGenerator.nextId();
            ids.add(id);
            System.out.println(id);
        }
        long id = ids.get(8);
        IdInfo info = new IdInfo(id);
        System.out.println(info);
        //SnowflakeIdGenerator.IdInfo info = SnowflakeIdGenerator.parse(id);
        System.out.println("時間戳: " + new Date(info.timestamp));
        System.out.println("數(shù)據(jù)中心 ID: " + info.dataCenterId);
        System.out.println("工作節(jié)點 ID: " + info.workerId);
        System.out.println("序列號: " + info.sequence);
    }
    /**
     * 解析 Snowflake ID
     *
     * @param id Snowflake ID
     * @return 包含時間戳、數(shù)據(jù)中心 ID、工作節(jié)點 ID 和序列號的結(jié)構(gòu)體
     */
    public static IdInfo parse(long id) {
        long timestamp = (id >> TIMESTAMP_LEFT_SHIFT) + EPOCH;
        long dataCenterId = (id >> DATA_CENTER_ID_SHIFT) & MAX_DATA_CENTER_ID;
        long workerId = (id >> WORKER_ID_SHIFT) & MAX_WORKER_ID;
        long sequence = id & MAX_SEQUENCE;
        return new IdInfo(timestamp, dataCenterId, workerId, sequence);
    }
}

UUID遞增方式

優(yōu)點:

  1. 全局唯一性‌:UUID確保在任何情況下都能生成唯一的標識符,這對于分布式系統(tǒng)尤為重要。
  2. 無需數(shù)據(jù)庫級別的唯一性檢查‌:插入數(shù)據(jù)時不需要檢查其他記錄,減少了數(shù)據(jù)庫的負擔。
  3. 易于遷移‌:在數(shù)據(jù)庫架構(gòu)遷移或數(shù)據(jù)遷移時,UUID的唯一性保證了數(shù)據(jù)的完整性。

缺點:

  1. 占用空間大‌:UUID通常以128位表示,轉(zhuǎn)換為字符串后長度較長(36個字符,包括4個破折號),占用更多的存儲空間。
  2. 性能問題‌:在大量插入操作時,UUID的隨機性和無序性可能導(dǎo)致數(shù)據(jù)庫性能下降,因為它們不遵循順序插入,可能會引起索引分裂和碎片化。
  3. 不適合作為主鍵進行排序‌:由于UUID的隨機性,基于UUID的排序效率較低。

核心結(jié)構(gòu)與生成原理

  1. 數(shù)據(jù)結(jié)構(gòu)與表示形式‌:雪花算法生成的ID是一個‌64位的長整型數(shù)字‌,其二進制結(jié)構(gòu)通常包含時間戳、機器標識(或數(shù)據(jù)中心ID)和序列號等部分。而UUID是一個‌128位的全局唯一標識符‌,通常以32個十六進制數(shù)字組成的字符串形式呈現(xiàn)(例如 550e8400-e29b-41d4-a716-446655440000)。‌‌
  2. 生成機制‌:雪花算法的唯一性依賴于‌系統(tǒng)時間戳、預(yù)設(shè)的機器/數(shù)據(jù)中心編號以及同一毫秒內(nèi)的序列號‌的組合,這使其生成過程需要一定的配置(如分配節(jié)點ID)。UUID的生成算法則更為多樣(有多個版本),其原理可能基于MAC地址、時間戳、隨機數(shù)或命名空間等,‌生成過程簡單,通常無需中心化協(xié)調(diào)或復(fù)雜配置‌。‌‌

性能與適用場景差異

  1. 有序性與數(shù)據(jù)庫性能‌:這是兩者最關(guān)鍵的差異。雪花算法生成的ID‌基本按時間趨勢遞增‌,具有時間有序性。當這種有序ID作為數(shù)據(jù)庫主鍵時,新記錄會順序插入B+樹索引的末尾,‌大大提升了寫入性能并減少了頁分裂‌。相反,傳統(tǒng)的UUID(如UUIDv4)‌是完全無序的‌,作為主鍵插入會導(dǎo)致隨機寫入,可能嚴重拖慢數(shù)據(jù)庫操作。值得注意的是,較新的UUIDv7版本‌引入了時間戳,也具備了時間有序性‌。‌‌
  2. 存儲與傳輸效率‌:雪花算法的64位整數(shù)在數(shù)據(jù)庫中通常用 BIGINT(8字節(jié))存儲,‌空間占用小,索引結(jié)構(gòu)更緊湊‌。UUID若以字符串形式(如 CHAR(36))存儲,則需占用更多空間;即便使用二進制格式(BINARY(16),16字節(jié)),其長度仍是雪花算法的兩倍,‌在存儲和網(wǎng)絡(luò)傳輸中開銷更大‌。‌‌
  3. 分布式部署簡易性‌:UUID‌無需任何節(jié)點標識配置‌,在任何地方均可獨立生成,天生適合高度解耦的分布式架構(gòu)。雪花算法在分布式部署時,‌需要為每個生成節(jié)點分配唯一的工作ID(WorkId)‌,這引入了額外的管理復(fù)雜度。‌‌
  4. 信息可解析性與安全性‌:雪花算法ID的組成部分(如時間戳、機器ID)‌可以被反解出來‌,便于問題排查和業(yè)務(wù)分析,但也可能泄露部署信息。傳統(tǒng)UUID(如基于隨機數(shù)的v4)‌內(nèi)容不可解析‌,不包含敏感信息。‌‌

考量與實踐建議

  1. 根據(jù)系統(tǒng)架構(gòu)與需求選擇‌:
    • 優(yōu)先選擇雪花算法‌的場景:需要‌高性能數(shù)據(jù)庫寫入與查詢‌、ID‌按時間排序‌(如評論、訂單時序展示)、以及對‌存儲空間有嚴格要求‌的分布式系統(tǒng)。‌‌
    • 優(yōu)先選擇UUID‌的場景:系統(tǒng)架構(gòu)‌簡單‌、或?qū)?zwnj;生成簡便性和部署靈活性要求極高‌、且對數(shù)據(jù)庫索引性能不敏感的場景。若需要有序性但不想管理節(jié)點ID,可考慮‌UUIDv7‌。‌
  2. 注意潛在風(fēng)險與優(yōu)化‌:
    • 雪花算法‌強依賴系統(tǒng)時鐘‌。若發(fā)生時鐘回撥(如NTP校準),可能導(dǎo)致ID重復(fù)。實踐中需通過記錄最大ID、暫停服務(wù)或使用邏輯時鐘等手段防范。‌‌
    • 使用UUID作為數(shù)據(jù)庫主鍵時,‌建議采用 BINARY(16) 存儲‌以減少空間占用,并評估其對寫入性能的實際影響。‌‌

總結(jié) 

到此這篇關(guān)于Java版雪花算法生成ID實用工具類的文章就介紹到這了,更多相關(guān)Java雪花算法生成ID工具類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mac下如何查看已安裝的jdk版本及其安裝目錄

    Mac下如何查看已安裝的jdk版本及其安裝目錄

    這篇文章主要介紹了Mac下如何查看已安裝的jdk版本及其安裝目錄問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • java中的Serializable、transient關(guān)鍵字詳解

    java中的Serializable、transient關(guān)鍵字詳解

    這篇文章主要介紹了java中的Serializable、transient關(guān)鍵字詳解,序列化只會保存屬性值,不會保存方法,通過反序列化可以把序列化后的內(nèi)容恢復(fù)成對象,需要的朋友可以參考下
    2023-09-09
  • java中獲取json的所有key方法

    java中獲取json的所有key方法

    下面小編就為大家分享一篇java中獲取json的所有key方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • Spring?Boot整合阿里開源中間件Canal實現(xiàn)數(shù)據(jù)增量同步

    Spring?Boot整合阿里開源中間件Canal實現(xiàn)數(shù)據(jù)增量同步

    這篇文章主要為大家介紹了Spring?Boot整合阿里開源中間件Canal實現(xiàn)數(shù)據(jù)增量同步示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • java類與對象案例之打字游戲

    java類與對象案例之打字游戲

    這篇文章主要為大家詳細介紹了java類與對象案例之打字游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • Java 1.8使用數(shù)組實現(xiàn)循環(huán)隊列

    Java 1.8使用數(shù)組實現(xiàn)循環(huán)隊列

    這篇文章主要為大家詳細介紹了Java 1.8使用數(shù)組實現(xiàn)循環(huán)隊列,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • 圖解Java經(jīng)典算法快速排序的原理與實現(xiàn)

    圖解Java經(jīng)典算法快速排序的原理與實現(xiàn)

    快速排序是基于二分的思想,對冒泡排序的一種改進。主要思想是確立一個基數(shù),將小于基數(shù)的數(shù)放到基數(shù)左邊,大于基數(shù)的數(shù)字放到基數(shù)的右邊,然后在對這兩部分進一步排序,從而實現(xiàn)對數(shù)組的排序
    2022-09-09
  • java ThreadPoolExecutor 并發(fā)調(diào)用實例詳解

    java ThreadPoolExecutor 并發(fā)調(diào)用實例詳解

    這篇文章主要介紹了java ThreadPoolExecutor 并發(fā)調(diào)用實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 基于Java實現(xiàn)記事本功能

    基于Java實現(xiàn)記事本功能

    這篇文章主要為大家詳細介紹了基于Java實現(xiàn)記事本功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • java8中Map的一些騷操作總結(jié)

    java8中Map的一些騷操作總結(jié)

    這篇文章主要給大家介紹了關(guān)于java8中Map的一些騷操作,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02

最新評論

奈曼旗| 江阴市| 金乡县| 武夷山市| 信阳市| 日照市| 青冈县| 古交市| 河北省| 防城港市| 广灵县| 耿马| 洛阳市| 四平市| 桂东县| 德昌县| 西乌| 云林县| 黄大仙区| 桓台县| 英超| 忻城县| 交口县| 临江市| 五华县| 普兰县| 会同县| 喀喇| 淮南市| 都匀市| 许昌市| 凭祥市| 长岭县| 兴隆县| 高碑店市| 石棉县| 金乡县| 化隆| 昌都县| 铜川市| 山东|