找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

32

积分

0

好友

6

主题
发表于 2025-10-25 01:30:08 | 查看: 27| 回复: 0

在软件开发中,生成唯一标识符是一个基础且重要的需求。无论是数据库记录分配、用户会话管理、分布式系统设计,还是多线程编程中的对象标识,都需要可靠的唯一ID生成方案。本文将详细介绍C++中7种常用的唯一ID生成方法。

1. 时间戳生成法

实现原理

利用系统当前时间戳生成唯一ID,支持Unix时间戳和精确到毫秒/微秒的高精度时间戳。

#include <iostream>
#include <chrono>

std::string generateUniqueId() {
    auto now = std::chrono::high_resolution_clock::now();
    auto duration = now.time_since_epoch();
    long long timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
    return std::to_string(timestamp);
}

int main() {
    std::cout << "Unique ID: " << generateUniqueId() << std::endl;
    return 0;
}

优缺点分析

  • 优点:实现简单,ID具有递增特性,时间精度高
  • 缺点:高并发场景下可能出现重复ID

2. UUID生成法

UUID(通用唯一标识符)是128位的全局唯一标识符标准,格式为:550e8400-e29b-41d4-a716-446655440000。

#include <iostream>
#include <random>
#include <iomanip>
#include <sstream>

std::string generateUUID() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<int> dist(0, 15);

    std::stringstream ss;
    ss << std::hex;

    for (int i = 0; i < 8; ++i) ss << dist(gen);
    ss << "-";
    for (int i = 0; i < 4; ++i) ss << dist(gen);
    ss << "-";
    for (int i = 0; i < 4; ++i) ss << dist(gen);
    ss << "-";
    for (int i = 0; i < 4; ++i) ss << dist(gen);
    ss << "-";
    for (int i = 0; i < 12; ++i) ss << dist(gen);

    return ss.str();
}

int main() {
    std::cout << "Generated UUID: " << generateUUID() << std::endl;
    return 0;
}

优缺点分析

  • 优点:全球唯一性保证,不依赖系统时钟
  • 缺点:字符串长度较长,存储空间占用大

3. 序列号生成法

基于自增序列的ID生成方案,适用于单机环境。

#include <iostream>
#include <atomic>

class IDGenerator {
public:
    IDGenerator() : current_id(0) {}

    std::string generateUniqueId() {
        current_id.fetch_add(1);
        return std::to_string(current_id);
    }

private:
    std::atomic<long long> current_id;  // 原子操作确保线程安全
};

int main() {
    IDGenerator idGen;
    std::cout << "Unique ID: " << idGen.generateUniqueId() << std::endl;
    return 0;
}

优缺点分析

  • 优点:实现简单,ID递增易维护
  • 缺点:系统重启或分布式环境可能产生冲突

4. Snowflake分布式ID生成法

结合机器标识和时间戳的分布式ID生成方案。

#include <iostream>
#include <chrono>
#include <random>
#include <bitset>

class SnowflakeIdGenerator {
public:
    SnowflakeIdGenerator(int nodeId) : nodeId(nodeId) {}

    long long generateUniqueId() {
        auto now = std::chrono::high_resolution_clock::now();
        auto duration = now.time_since_epoch();
        long long timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();

        return (timestamp << 22) | (nodeId << 12) | (random() & 0xFFF);
    }

private:
    int nodeId;  // 机器ID
    std::random_device rd;

    int random() {
        std::uniform_int_distribution<int> dist(0, 4095);
        return dist(rd);
    }
};

int main() {
    SnowflakeIdGenerator generator(1);  // 设置机器ID为1
    std::cout << "Generated Unique ID: " << generator.generateUniqueId() << std::endl;
    return 0;
}

优缺点分析

  • 优点:适用于分布式系统,保证节点唯一性
  • 缺点:实现复杂,需要全局时钟同步

5. 哈希值生成法

基于输入数据的哈希运算生成唯一ID。

#include <iostream>
#include <sstream>
#include <iomanip>
#include <openssl/md5.h>

std::string generateHashId(const std::string& input) {
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5_CTX md5Context;

    MD5_Init(&md5Context);
    MD5_Update(&md5Context, input.c_str(), input.length());
    MD5_Final(digest, &md5Context);

    std::stringstream ss;
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        ss << std::setw(2) << std::setfill('0') << std::hex << (int)digest[i];
    }

    return ss.str();
}

int main() {
    std::string input = "unique_input_data";
    std::cout << "Generated Hash ID: " << generateHashId(input) << std::endl;
    return 0;
}

优缺点分析

  • 优点:ID长度固定,生成速度快
  • 缺点:输入数据相似时可能产生哈希冲突

6. 数据库自增ID法

利用数据库的自增主键特性生成唯一ID。

#include <mysql/mysql.h>
#include <iostream>

long long getAutoIncrementId(MYSQL* conn) {
    MYSQL_RES* res;
    MYSQL_ROW row;

    mysql_query(conn, "SELECT LAST_INSERT_ID()");
    res = mysql_store_result(conn);
    row = mysql_fetch_row(res);

    return std::stoll(row[0]);
}

int main() {
    MYSQL* conn;
    conn = mysql_init(NULL);

    if (mysql_real_connect(conn, "localhost", "user", "password", "database", 0, NULL, 0)) {
        std::cout << "Last inserted ID: " << getAutoIncrementId(conn) << std::endl;
    } else {
        std::cerr << "Connection failed!" << std::endl;
    }

    mysql_close(conn);
    return 0;
}

优缺点分析

  • 优点:数据库保证唯一性,管理简单
  • 缺点:依赖数据库,不适用于分布式场景

7. 方法选择指南

根据不同的应用场景选择合适的ID生成方案:

  • 单机应用:时间戳、序列号、哈希值方法足够满足需求
  • 分布式系统:Snowflake等基于机器ID和时间戳的方案更为适合
  • 数据库环境:数据库自增ID在单一数据库场景下表现良好

每种方法都有其适用的场景,开发者应根据具体需求选择最合适的ID生成策略。

标签: C++,UUID,Snowflake,分布式系统,ID生成,哈希算法,数据库

来自圈子: 面试专业户
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-11-5 21:33 , Processed in 0.053064 second(s), 36 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表