【java面试100问】84 为什么不推荐使用数据库自增主键?也不推荐使用UUID作主键,用雪花算法会有什么问题?

文摘   2025-01-18 07:43   天津  

 

为什么不推荐使用数据库自增主键?

自增主键,顾名思义,就是每次插入新记录时,主键值会自动递增。

虽然这种方法简单易用,但在很多场景下并不推荐,原因如下:

  1. 1. 安全性问题:自增主键容易被外部用户猜测,这可能导致安全漏洞。

比如,黑客可以通过简单的递增逻辑猜测下一条记录的主键,从而获取敏感数据。

  1. 2. 性能问题:在高并发环境下,自增主键可能会成为性能瓶颈。

多个节点同时插入数据时,需要协调生成主键,确保唯一性,这会增加系统的复杂性和延迟。

  1. 3. 数据分布不均:自增主键在数据库中的存储是按顺序插入的,这可能导致数据在磁盘上的分布不均,影响查询性能。
  2. 4. 难以实现多主分片架构:在多主分片架构中,确保主键的唯一性是一个挑战。

自增主键需要不同节点之间协调生成,增加了系统的复杂性和延迟。

为什么不推荐使用UUID作主键?

UUID是一种全局唯一标识符,虽然它解决了自增主键的很多问题,但也有一些显著的缺点:

  1. 1. 性能问题:UUID是随机生成的,每次插入数据时,新的UUID可能需要插入到索引树的中间位置,这可能导致频繁的页分裂,降低性能。
  2. 2. 占用内存:UUID通常是一个较长的字符串(36个字符),相比整数主键,它占用的内存更多,这也会影响索引树的效率。
  3. 3. 索引效率低:由于UUID是随机生成的,索引效率通常低于有序的整数主键。

雪花算法会有什么问题?

雪花算法(Snowflake)是Twitter提出的一种分布式自增ID算法,它生成的ID是全局唯一的,并且大致递增。

虽然雪花算法在很多场景下表现优异,但也有一些潜在的问题:

  1. 1. 依赖系统时间:雪花算法依赖系统时间生成ID,如果系统时间被回调或改变,可能会导致ID冲突或重复。
  2. 2. 时钟同步问题:在分布式系统中,不同机器上的时钟可能无法完全同步,这可能导致生成的ID不是全局递增的。

虽然这通常不会影响ID的唯一性,但在某些严格要求递增的场景下可能不适用。

  1. 3. 节点数量限制:雪花算法中用于记录工作机器ID的位数是有限的(通常是10位),这意味着最多只能支持1024个节点。

如果节点数量超过这个限制,就需要进行额外的扩展。

示例代码

下面是一个简单的雪花算法Java实现示例:

public classSnowflakeIdGenerator {
    // 其他常量、变量和方法...

    // 构造函数
    publicSnowflakeIdGenerator(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            thrownewIllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            thrownewIllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    // 生成下一个ID
    publicsynchronizedlongnextId() {
        longcurrStmp= getNewstmp();
        if (currStmp < lastStmp) {
            thrownewRuntimeException("Clock moved backwards. Refusing to generate id");
        }
        if (currStmp == lastStmp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            sequence = 0L;
        }
        lastStmp = currStmp;
        return ((currStmp - START_STMP) << TIMESTAMP_LEFT) |
               (datacenterId << DATACENTER_LEFT) |
               (machineId << MACHINE_LEFT) |
               sequence;
    }

    // 其他辅助方法...
}

总结

选择数据库主键时,需要根据具体场景和需求进行权衡。

自增主键简单易用,但在高并发、分布式环境下可能存在问题;

UUID虽然解决了自增主键的很多问题,但性能上可能不如整数主键;

雪花算法则是一种折中的方案,但在实际应用中也需要考虑时钟同步、节点数量限制等问题。


希望文章能给大家带来点技术收获。也希望大家能够点赞收藏转发,让知识成为大家的财富。你的支持,是我最大的动力!

  

你诺喜欢,请点个关注

大家可以发送消息:202501

领取计算机黑皮书191本(1月有效)


推荐文章:

推荐java面试100题讲解源文件

推荐Spring Cloud Alibaba笔记


夏壹分享
系统化技术讲解,每日精进,为后端技术人员打造的知识充电站!
 最新文章