数据库如何合理生成主键:UUID、雪花算法

news/2024/11/15 7:27:55/

目录

1.使用自增主键的弊端

2.主键生成算法

2.1.UUID

2.1.1.概述

2.1.2.JAVA中的UUID

2.2.雪花算法

2.2.1.概述

2.2.2.JAVA中使用雪花算法


1.使用自增主键的弊端

首先在实际工程中我们很少用1,2,3......这样的自增主键,原因如下:

  • 主键冲突
  • 性能问题
  • 安全问题

主键冲突:

比如我要跨数据库进行数据同步、或者在分布式系统中跨“分区”进行数据同步,不难想象,1,2,3......这种递增的单数字是极容易产生冲突的。

性能问题:

自增主键在数据库中使用的是自增序列来生成主键值,而在高并发情况下,多个线程可能同时请求获取下一个自增值,此时会发生竞争,因为数据库需要保证每个自增值只会被分配一次。为了保证自增值的唯一性,数据库使用锁机制来避免多个线程同时获取同一个自增值。

安全问题:

使用自增主键可以很容易地猜测出下一条记录的主键值,这可能会导致一些安全问题。

综上所述,我们可以发现使用复杂主键是很有必要的,要生成复杂且具有唯一性的主键就需要依赖主键生成算法了。

2.主键生成算法

常见的主键生成算法:

  • UUID
  • 雪花算法

2.1.UUID

2.1.1.概述

UUID,通用唯一标识符,UUID算法的核心思想是生成一个128位的唯一标识符,通常表示为32个十六进制数字的字符串。每个UUID会尽量保证其唯一性。

UUID算法目前有几个官方推出的版本,由Internet工程任务组(IETF)、国际标准化组织(ISO)和国际电信联盟(ITU)共同制定:

  1. UUIDv1:基于时间戳和MAC地址生成UUID,保证同一台计算机上生成的UUID是唯一的,但不适合在分布式系统中使用。

  2. UUIDv2:基于DCE安全机制的UUID,使用POSIX的UID/GID和当前时间生成UUID,不常用。

  3. UUIDv3:基于命名空间和字符串生成UUID,使用MD5散列算法生成UUID。

  4. UUIDv4:使用随机数生成UUID,保证在所有计算机上都是唯一的。

  5. UUIDv5:与UUIDv3类似,但使用SHA-1散列算法生成UUID。

其实本质上来说UUID只是个概念,UUID的算法我们甚至可以自己去写一个,只是我们自己写的肯定会没那么优质,保证唯一性的效果不会好。

2.1.2.JAVA中的UUID

工程上我们一般都是在JAVA后端生成UUID作为每条要插入数据库的数据的主键,JAVA中生成UUID很简单:

import java.util.UUID;public class UUIDExample {public static void main(String[] args) {// 生成一个随机的UUIDUUID uuid = UUID.randomUUID();System.out.println("Random UUID: " + uuid.toString());}
}

生成过程其实也很简单:

public static UUID randomUUID() {SecureRandom ng = Holder.numberGenerator;byte[] randomBytes = new byte[16];ng.nextBytes(randomBytes);randomBytes[6]  &= 0x0f;  /* clear version        */randomBytes[6]  |= 0x40;  /* set to version 4     */randomBytes[8]  &= 0x3f;  /* clear variant        */randomBytes[8]  |= 0x80;  /* set to IETF variant  */return new UUID(randomBytes);
}
  1. 首先从Holder静态内部类中获取一个SecureRandom对象。Holder类是一个懒加载的单例类,用于确保SecureRandom对象只被创建一次,并且线程安全。

  2. 然后生成一个长度为16的字节数组randomBytes,使用ng.nextBytes(randomBytes)方法填充随机数。

  3. 接下来将字节数组randomBytes中的一些特定位进行修改,以符合UUID版本4的格式要求:

    • 将第7个字节的高4位清零,再将其低4位设置为4,表示这是UUID版本4。
    • 将第9个字节的高2位清零,再将其第7位设置为1,表示这是符合IETF标准的UUID。
  4. 最后,将修改后的字节数组作为参数,调用UUID(byte[] data)构造方法生成一个UUID对象。

2.2.雪花算法

2.2.1.概述

雪花算法(Snowflake Algorithm)是Twitter公司开发的一种分布式ID生成算法,用来生成64位的唯一ID。它的核心思想是:利用一个64位的long型数字作为全局唯一ID,高位部分表示时间戳,中间部分表示机器ID,低位部分表示在此机器上的序列号。

雪花算法的64位long型数字由以下几个部分组成:

  • 符号位(1 bit):由于long型数字是有符号的,而雪花算法生成的ID必须是正数,所以符号位固定为0。
  • 时间戳部分(41 bit):记录时间戳,精确到毫秒级别,可以使用当前时间减去一个固定的起始时间,得到一个相对时间戳,从而可以使用41位二进制数表示该时间戳可支持的时间范围为约69年。
  • 机器ID部分(10 bit):可以配置多台机器,每台机器都分配一个唯一的ID,用于在分布式环境下防止ID重复。
  • 序列号部分(12 bit):表示在同一毫秒内生成的序列号,可以使用自增来实现,最多支持4096个ID。

2.2.2.JAVA中使用雪花算法

原生JDK中并没有提供雪花算法的实现,在一些常用的ORM框架中支持了使用雪花算法生成主键ID的功能,如hibernate、mybatis-plus。

以使用Hibernate为例:

可以在实体类的主键字段上使用@GenericGenerator注解和@GeneratedValue注解,其中@GenericGenerator注解用来指定主键生成器的名称和类型,@GeneratedValue注解则用来指定主键生成策略和生成器的名称,例如:

@Entity
@Table(name = "user")
public class User {@Id@GenericGenerator(name = "snowflake", strategy = "com.xxx.snowflake.SnowflakeIdGenerator")@GeneratedValue(generator = "snowflake")@Column(name = "id")private Long id;// ...
}

以mybatis-plus为例:

配置主键生成器为雪花算法的生成器

mybatis-plus:
  global-config:
    db-config:
      id-type: ASSIGN_ID
      key-generator: com.baomidou.mybatisplus.core.incrementer.SnowflakeKeyGenerator

然后给主件指定使用所配置的主键生成器

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;@Data
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String name;private Integer age;// 其他字段省略...
}


http://www.ppmy.cn/news/99314.html

相关文章

【算法题解】31. 翻转二叉树的递归解法

这是一道 简单 题 https://leetcode.cn/problems/invert-binary-tree/ 题目 给你一棵二叉树的根节点 r o o t root root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6…

【openGauss实战11】性能报告WDR深度解读

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…

车载软件架构 —— 功能安全与基础软件

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 在最艰难的时候,自己就别去幻想太远的将来,只要鼓励自己过好今天就行了! 这世…

基于SpringBoot养老院管理系统

目录 一、项目介绍 二. 运行环境 三、项目技术 四、部署项目 五、项目运行 六、项目展示 五、项目下载 一、项目介绍 基于springboot的养老院管理系统拥有多种角色账号:管理员和用户 管理员:管理员管理、用户管理、健康管理、病例方案管理、药品…

机器学习-线性代数-矩阵与空间映射

矩阵 文章目录 矩阵直观理解特殊矩阵矩阵的基本运算矩阵( A A A)乘向量( x x x)的本质:改变空间位置矩阵:空间映射关系矮胖矩阵对空间的降维压缩高瘦矩阵无法覆盖目标空间方阵映射矩阵的秩 直观理解 一个 m n m \times n mn的大小矩阵,直观…

VSCODE 插件推荐

文章目录 项目管理Project Manager markdownmarkdown-pdfPaste ImageMarkdown Preview Enhanced 笔记Notes 思维导图vscode-mindmap 开发Visual Studio IntelliCode GitHub Repositories 项目管理 Project Manager 以下是项目管理器提供的一些功能: 将任何文件夹…

[元带你学: eMMC协议详解 12] Speed Mode 选择

依JEDEC eMMC 5.1及经验辛苦整理,付费内容,禁止转载。 所在专栏 《元带你学: eMMC协议详解》 内容摘要 全文 2000字, 介绍了各种Speed Mode 选择的方法, 需要按照一定的步骤, 重点需要掌握HS400, High Speed 和 HS20…

什么是分段路由?如何在网络中实施分段路由?

在计算机网络中,分段路由(Subnetting)是一种将一个大的网络划分为多个较小子网的技术。它允许网络管理员更有效地分配 IP 地址和管理网络流量。本文将详细介绍分段路由的概念、原理以及如何在网络中实施分段路由。 1. 分段路由的概念 分段路…