数据库中生成主键的方式及其优缺点

数据库中生成主键的方式及其优缺点

一、自动增长(AUTO_INCREMENT)

使用方法:设置auto_increment 实现数据表自增;
优点

  1. 简单易用:自增主键是一种简单的方式,只需在数据库表中设置自增属性即可,无需在代码中进行繁琐的处理。
  2. 唯一性:自增主键保证了每个新记录都有唯一的主键值,避免了主键冲突的可能性。

缺点

  1. 可预测性:自增主键通常是按照顺序递增的,这意味着主键值的分布是有序的。有些情况下,这可能会暴露敏感信息,例如可以推测出系统的数据规模或活跃程度。
  2. 不适用于分布式环境:在分布式环境下,不同节点生成的自增主键可能会冲突,导致主键冲突问题。此时需要额外的机制来保证主键的唯一性。
  3. 不可回收:一旦使用了自增主键,删除的记录之后产生的主键值将不会被再次使用,可能导致主键的浪费。
  4. 分表实现比较麻烦:在分库分表中,保证每张表实现自增同时,不同表之间还得保证连续。所以分表实现比较麻烦;假设有三张表,主键分别为下图所示的id,当我们操作第二张表的时候需要根据上一张表的最后那个数据的id值来进行划分。
    在这里插入图片描述

适用场景

  1. 单节点系统:在单节点的系统中,自增主键是一种方便且高效的方式,不需要额外的复杂处理逻辑。
  2. 数据规模较小且无需保密性的系统:如果数据规模较小且无需保密性,使用自增主键可以简化开发过程,减少复杂性。
  3. 需要确保主键的唯一性的系统:自增主键可以确保每个记录都有唯一的主键值,避免了主键冲突的可能性。

二、使用JDK生成UUID作为主键

使用方法
在Java中,可以使用JDK提供的UUID类来生成UUID。以下是生成UUID的示例代码:

import java.util.UUID;public class Main {public static void main(String[] args) {// 生成新的UUIDUUID uuid = UUID.randomUUID();System.out.println(uuid.toString());// 将UUID转换为字符串形式,去掉中间的"-"符号String uuidString = uuid.toString().replace("-", "");System.out.println(uuidString);}
}

上述代码首先使用UUID.randomUUID()方法生成一个新的UUID对象,然后可以使用toString()方法将UUID转换为字符串形式。如果想去掉中间的"-"符号,可以使用replace("-", "")方法进行替换。最后,可以通过调用System.out.println()方法将UUID打印出来。

优点

  1. 唯一性:UUID是基于时间戳、网卡MAC地址和随机数生成的,几乎可以保证全球范围内的唯一性。
  2. 生成简单:JDK中提供了UUID类,可以很方便地生成UUID。
  3. 可以在分布式环境中使用:UUID的唯一性使其在分布式系统中可以作为全局唯一标识符。

缺点

  1. 长度较长:UUID是由16个字节组成的128位数字,相比于自增长的整数主键,长度较长。
  2. 不易读:UUID通常以字符串的形式表示,由一串数字和字母组成,不易于人类阅读。

适用场景

  1. 数据库表主键:在数据库表中,使用UUID作为主键可以保证数据的唯一性。
  2. 分布式系统中的唯一标识符:在分布式系统中,使用UUID可以生成全局唯一的标识符,用于唯一标识不同节点或对象。

三、使用雪花算法(Snowflake)生成的ID作为主键

使用方法
以下是一个简单的示例代码,演示如何使用Java实现雪花算法生成唯一ID:

public class SnowflakeIdGenerator {// 起始的时间戳,2022-01-01 00:00:00private final long twepoch = 1641004800000L;// 每个部分占用的位数private final long workerIdBits = 5L; // 机器标识位数private final long dataCenterIdBits = 5L; // 数据中心标识位数private final long sequenceBits = 12L; // 序列号位数// 每个部分的最大值private final long maxWorkerId = -1L ^ (-1L << workerIdBits);private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);private final long sequenceMask = -1L ^ (-1L << sequenceBits);// 每个部分向左的位移private final long workerIdShift = sequenceBits;private final long dataCenterIdShift = sequenceBits + workerIdBits;private final long timestampShift = sequenceBits + workerIdBits + dataCenterIdBits;private long workerId; // 机器IDprivate long dataCenterId; // 数据中心IDprivate long sequence = 0L; // 序列号private long lastTimestamp = -1L; // 上次生成ID的时间戳public SnowflakeIdGenerator(long workerId, long dataCenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException("Worker ID超出范围");}if (dataCenterId > maxDataCenterId || dataCenterId < 0) {throw new IllegalArgumentException("Data Center ID超出范围");}this.workerId = workerId;this.dataCenterId = dataCenterId;}public synchronized long generateId() {long timestamp = System.currentTimeMillis();// 如果当前时间小于上次生成ID的时间戳,说明系统时钟回退过,抛出异常if (timestamp < lastTimestamp) {throw new RuntimeException("系统时钟回退,无法生成ID");}// 如果是同一毫秒内生成的ID,自增序列号if (timestamp == lastTimestamp) {sequence = (sequence + 1) & sequenceMask;// 序列号溢出,等待下一毫秒if (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;return ((timestamp - twepoch) << timestampShift)| (dataCenterId << dataCenterIdShift)| (workerId << workerIdShift)| sequence;}private long tilNextMillis(long lastTimestamp) {long timestamp = System.currentTimeMillis();while (timestamp <= lastTimestamp) {timestamp = System.currentTimeMillis();}return timestamp;}public static void main(String[] args) {SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);long id = idGenerator.generateId();System.out.println("生成的ID:" + id);}
}

以上代码演示了一个简单的雪花算法ID生成器。在main方法中,创建了一个SnowflakeIdGenerator对象,然后调用generateId方法生成一个唯一的ID,并将其打印出来。

在实际应用中,需要根据需要调整各个部分的位数,以及机器标识和数据中心标识的取值范围。此外,为了确保在多线程环境下的线程安全性,生成ID的方法被声明为synchronized。

优点

  1. 全局唯一性:雪花算法生成的ID在全局范围内是唯一的,可以用于分布式系统中避免主键冲突的问题。
  2. 有序性:由于雪花算法生成的ID是基于时间戳的,所以生成的ID是按照时间先后顺序排序的,可以方便地根据ID查询按时间排序的数据。

缺点

  1. 依赖机器时钟:雪花算法生成的ID中的时间戳依赖于机器的时钟,如果机器的时钟回拨或者不同机器的时钟不同步,可能会导致生成的ID不唯一或者不符合预期的顺序。
  2. 可读性较差:雪花算法生成的ID是一个64位的整数,对于人类来说可读性较差,不如自增ID或者UUID直观。

适用场景

  1. 数据库分库分表:在分库分表的系统中,需要生成唯一的主键来保证数据的一致性和查询的效率。
  2. 分布式任务调度:在分布式任务调度系统中,每个任务需要有一个唯一的标识作为主键,用于任务的调度和追踪。
  3. 分布式日志记录:在分布式系统中,每条日志需要有一个唯一的ID,方便日志的聚合和查询。

四、使用Redis的原子命令INCR或INCRBY生成主键

使用方法
在Java中使用Redis生成主键,可以使用Redis的原子命令INCR或INCRBY。
示例代码如下:

import redis.clients.jedis.Jedis;public class RedisPrimaryKeyGenerator {private static final String REDIS_HOST = "localhost";private static final int REDIS_PORT = 6379;private static final String KEY_NAME = "primary_key";public static void main(String[] args) {// 创建Jedis对象Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT);// 生成主键long primaryKey = generatePrimaryKey(jedis);System.out.println("Generated Primary Key: " + primaryKey);// 关闭连接jedis.close();}private static long generatePrimaryKey(Jedis jedis) {// 使用INCR命令递增主键return jedis.incr(KEY_NAME);}
}

上述代码通过创建Jedis对象连接到Redis服务器,然后使用jedis.incr(KEY_NAME)命令递增名为"primary_key"的键,从而生成唯一的主键。

优点

  1. 高性能:Redis是一个内存数据库,具有非常高的读写性能,可以快速生成主键。
  2. 高并发:Redis支持多线程并发访问,可以同时处理多个生成主键的请求。
  3. 可扩展性:Redis支持分布式部署,可以通过搭建Redis集群来提高生成主键的容量和吞吐量。
  4. 高可靠性:Redis具有数据持久化的功能,可以在发生故障时快速恢复数据。

缺点

  1. 单点故障:如果Redis实例发生故障,可能会导致生成主键的过程停止。
  2. 数据一致性:由于Redis是内存数据库,数据可能会发生丢失或不一致的情况,造成生成的主键不可用。

适用场景

  1. 分布式系统:当多个节点需要生成唯一的主键时,可以使用Redis作为共享的主键生成器。
  2. 快速生成唯一ID:如果需要在高并发场景下快速生成唯一的ID,使用Redis可以提高性能和并发能力。
  3. 分布式锁:可以通过Redis生成的主键来实现分布式锁机制,保证系统的并发安全性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/13209.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

linux进程管理

进程和线程的关系 以下介绍为linux环境 进程是操作系统中一个运行中的程序&#xff0c;是资源分配和调度的基本单位。每个进程有自己独立的内存空间、文件描述符、堆栈等系统资源 线程&#xff08;Thread&#xff09; 是 CPU 调度的最小单位&#xff0c;是进程中的一个执行流…

unity基础,点乘叉乘。

简单记录下点乘叉乘&#xff0c;要不每次用完就忘&#xff0c;忘了又查。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class TestCrossDot : MonoBehaviour {/// <summary>/// 原点/// </summary>public Transform t…

Vue2+ElementUI:用计算属性实现搜索框功能

前言&#xff1a; 本文代码使用vue2element UI。 输入框搜索的功能&#xff0c;可以在前端通过计算属性过滤实现&#xff0c;也可以调用后端写好的接口。本文介绍的是通过计算属性对表格数据实时过滤&#xff0c;后附完整代码&#xff0c;代码中提供的是死数据&#xff0c;可…

JAVA学习日记(十二)查找算法

一、基本查找、二分查找 略 二、分块查找 将数组分块&#xff0c;每一个块中最大值小于后一个块中的最小值&#xff1a;块内无序&#xff0c;块间有序。 块&#xff1a;创建一个块类 按照规则划分好块之后&#xff0c;对要查询的值设计方法进行查询。 import java.util.…

多线程小知识

一. CAS CAS (Compare and Swap, 比较并交换) 是一种无锁编程技术, 用于实现多线程环境下对共享资源的线程安全访问. CAS 的核心思想是: 只有当内存中的值与预期值相匹配时, 才会将内存中的值更新为新值. 寄存器1中存放原值, 寄存器2中存放新值. 现在要将内存中的原值更新为新…

C++基础(12.红黑树实现)

目录 红黑树的概念&#xff1a; 红黑树规则&#xff1a; 红黑树如何确保最长路径不超过最短路径的2倍的&#xff1f; 红黑树的效率&#xff1a; 红黑树的插入: 红黑树树插入⼀个值的大概过程: 情况1&#xff1a;变色 情况2&#xff1a;单旋变色&#xff1a; 情况3&…

代码随想录算法训练营第二十天|39. 组合总和、40.组合总和II、131.分割回文串

39. 组合总和 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;带你学透回溯算法-组合总和&#xff08;对应「leetcode」力扣题目&#xff1a;39.组合总和&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩…

机器学习基础02_特征工程

目录 一、概念 二、API 三、DictVectorize字典列表特征提取 四、CountVectorize文本特征提取 五、TF-IDF文本1特征词的重要程度特征提取 六、无量纲化预处理 1、MinMaxScaler 归一化 2、StandardScaler 标准化 七、特征降维 1、特征选择 VarianceThreshold 底方差…

得物App入选诚信案例,10万正品样品库夯实高品质消费

近日&#xff0c;以“加强企业诚信建设 赋能经济社会发展”为主题的“2024年全国企业诚信建设大会”在烟台市召开。此次大会由中国企业联合会、中国企业家协会主办&#xff0c;山东省企业联合会、山东省企业家协会、烟台市企业联合会、烟台大学承办。大会期间&#xff0c;得物A…

036 RabbitMQ消息确认 死信队列 延时队列

文章目录 生产者确认模式application.propertiesMessageController.javaMessageConfirmRallback.java 生产者回退模式application.propertiesMessageConfirmRallback.javaMessageController.java 消费者手动确认application.propertiesConsumerAckQueueListener.java 死信队列延…

docker desktop运行rabittmq容器,控制台无法访问

docker desktop运行rabittmq容器&#xff0c;控制台无法访问 启动过程&#xff1a;…此处缺略&#xff0c;网上一大堆 原因 原因是在Docker上运行的RabbitMQ&#xff0c;默认情况下是没有启用管理插件和管理页面的 解决办法 使用命令 docker exec -it 容器id /bin/bash 进…

Tailwind 安装使用

Tailwind 安装使用 前言 CSS原子化——本文将详细介绍如何在Vue Vite npm环境下安装、配置并使用Tailwind CSS&#xff01; 文章目录 Tailwind 安装使用前言一、Tailwind 在 Vue Vite 项目中的安装1. 创建Vue项目2. 安装Tailwind CSS3. 初始化Tailwind配置4. 修改文件 tai…

centos7安装playwright踩坑记录

Python版本安装 Installation | Playwright Python 1. 安装pytest-playwright pip3 install pytest-playwright报错&#xff1a;提示找不到pytest-playwright 原因&#xff1a;服务器Python版本3.6.8太低&#xff0c;貌似pytest-playwright最低支持3.7 解决方法&#xff1…

函数(C语言)

1&#xff1a;函数的概念 函数的概念我们在初中的时候就已经听过了。 在C语言中也引入了函数&#xff0c;也可以叫子程序 C语言中的函数就是一个完成某项特定的任务的一小段代码 这段代码是有特殊的写法和调用方法的。其实C语言的程序也是由无数个小的函数组成的。 也就是&…

VMWare安装包及安装过程

虚拟机基本使用 检查自己是否开启虚拟化 如果虚拟化没有开启&#xff0c;需要自行开启&#xff1a;百度加上自己电脑的品牌型号&#xff0c;进入BIOS界面开启 什么是虚拟机 所谓的虚拟机&#xff0c;就是在当前计算机系统中&#xff0c;又开启了一个虚拟系统 这个虚拟系统&…

基于SVD奇异值分解的图像压缩算法(Python实现)

前言 SVD其实和PCA类似&#xff0c;就是丢入一个特征矩阵 X &#xff0c;输出另外一个特征矩阵 X′ , X′ 的维度要比原来的X 要低。并且里面的变量都是原来的变量的线性组合&#xff0c;所以含义也变得不好解释。 简单来说就是数据压缩&#xff0c;特征降维的一种技术&#…

国产AI图片工具,全部免费亲测实用!

近AI生图功能火出圈了&#xff0c;各家大厂都拿出了看家本领&#xff0c;今天就来聊聊即梦AI、通义万相、奇域AI和腾讯元宝的AI生图功能&#xff0c;看看它们各有什么特色吧&#xff01; 一、Dreamina 字节旗下的AI智能平台&#xff0c;简单实用的图片生成&#xff0c;对中国元…

C++ 二叉搜索树

二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的左右…

推荐一款3D建模软件:Agisoft Metashape Pro

Agisoft Metashape Pro是一款强大的多视点三维建模设计辅助软件&#xff0c;Agisoft Metashape是一款独立的软件产品&#xff0c;可对数字图像进行摄影测量处理&#xff0c;并生成3D空间数据&#xff0c;用于GIS应用&#xff0c;文化遗产文档和视觉效果制作&#xff0c;以及间接…

IntelliJ+SpringBoot项目实战(四)--快速上手数据库开发

对于新手学习SpringBoot开发&#xff0c;可能最急迫的事情就是尽快掌握数据库的开发。目前数据库开发主要流行使用Mybatis和Mybatis Plus,不过这2个框架对于新手而言需要一定的时间掌握&#xff0c;如果快速上手数据库开发&#xff0c;可以先按照本文介绍的方式使用JdbcTemplat…