问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

8种MySQL分库分表后主键ID生成策略,你选对了吗?

创作时间:
作者:
@小白创作中心

8种MySQL分库分表后主键ID生成策略,你选对了吗?

引用
CSDN
1.
https://blog.csdn.net/z_344791576/article/details/144644839

在MySQL进行分库分表之后,如何巧妙地生成全局唯一的主键ID?本文将详细介绍8种常见且实用的方法,包括数据库自增ID、UUID、Snowflake算法、Redis生成、MaxId表管理、Sequence特性、业务规则自定义以及Sharding-JDBC内置主键生成等。每种方法都配有具体的实现代码示例,并对其优缺点进行了分析。

嘿,小伙伴们!今天咱们要聊聊在MySQL进行分库分表之后,如何巧妙地生成全局唯一的主键ID。想象一下,如果你的系统正面临着海量数据的压力,而传统的单表设计已经无法满足需求,那么分库分表就是一种非常有效的解决方案。但是随之而来的问题是:如何确保每个分表中的主键ID既不冲突又能高效生成呢?别担心,接下来我将详细介绍几种常见且实用的方法,让你轻松应对这一挑战!

方法一:数据库自增ID + 分段设置

当采用自动生成主键ID方案时,可以通过为每张分表设定不同的起始点和步长来避免ID冲突。例如,如果有10张分表,则可以设置每张表的起始主键ID从1到10,步长均为10。这种方法简单易行,但适用于分表数量较为固定的情况。

优点:

  • 实现简单,几乎不需要额外开发工作。
  • 对于小规模应用来说性能足够好。

缺点:

  • 新增或删除分表时需要调整逻辑,灵活性较差。
  • 在高并发场景下可能会遇到性能瓶颈。

方法二:UUID作为主键

UUID(通用唯一标识符)由36个字符组成,能够保证全球范围内的唯一性。它非常适合用于那些对顺序没有严格要求的应用场景中,如分布式系统中的临时对象标识。

-- 使用UUID函数创建新记录
INSERT INTO my_table (id, name) VALUES (UUID(), 'example');

优点:

  • 完全随机生成,无需依赖特定数据库特性。
  • 易于实现跨平台迁移。

缺点:

  • 存储空间占用较大,索引效率较低。
  • 不利于构建有序索引,可能影响查询性能。

方法三:Snowflake算法

Twitter开源的Snowflake算法是一种基于时间戳、机器ID及序列号组合而成的64位整数型ID生成器。该方法不仅保证了ID的唯一性和递增性,还能很好地适应大规模并发环境下的快速发号需求。

// Java代码示例:使用Hutool库生成Snowflake ID
import cn.hutool.extra.snowflake.Snowflake;
import cn.hutool.extra.snowflake.IdUtil;
public class IdGenerator {
    private static final Snowflake snowflake = IdUtil.getSnowflake(1L, 1L);
    public static long nextId() {
        return snowflake.nextId();
    }
}

优点:

  • 支持极高并发量下的快速发号。
  • ID具有良好的可读性和排序特性。

缺点:

  • 依赖服务器时钟同步,若出现时钟回拨则可能导致重复ID问题。

方法四:Redis生成全局唯一ID

利用Redis的原子操作特性(如INCR),可以在多个实例间共享同一个计数器,从而实现高效的全局唯一ID分配机制。

# Redis命令行工具中执行
127.0.0.1:6379> INCR global_counter
(integer) 1

优点:

  • 操作简便快捷,适合高频次写入操作。
  • 可以结合业务规则生成带有日期等信息的复合ID。

缺点:

  • 需要引入额外组件,增加了系统的复杂度。
  • 如果Redis集群发生故障,可能会影响整个系统的可用性。

方法五:MaxId表集中管理

创建一张专门用于存储最大已用ID值的maxid表,并通过事务控制确保每次插入新记录前都能获取最新的可用ID。

CREATE TABLE `maxid` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50),
  `nextid` bigint(20),
  PRIMARY KEY (`id`)
);

-- 获取下一个可用ID
DELIMITER ;;
CREATE FUNCTION getid(myOrderId VARCHAR(50)) RETURNS BIGINT(20)
BEGIN
  UPDATE maxid SET nextid = nextid + 1 WHERE name = myOrderId;
  SELECT nextid INTO @result FROM maxid WHERE name = myOrderId;
  RETURN @result;
END;;
DELIMITER ;

优点:

  • 设计直观易于理解。
  • 对现有架构改动较小。

缺点:

  • 单点故障风险较高。
  • 在极端情况下可能导致性能下降。

方法六:Sequence特性(仅限Oracle/SQL Server)

对于支持Sequence特性的关系型数据库而言,可以直接利用这一功能来自动生成连续且唯一的ID值。不过需要注意的是,MySQL并不直接提供类似的内置功能。

-- 创建Sequence
CREATE SEQUENCE seq_order_id START WITH 1 INCREMENT BY 1;

-- 插入新记录时引用Sequence
INSERT INTO orders (order_id, customer_name) VALUES (seq_order_id.NEXTVAL, 'John Doe');

优点:

  • 简化了ID生成逻辑。
  • 与数据库事务紧密结合,保证数据一致性。

缺点:

  • 适用范围有限,仅限于特定类型的数据库产品。

方法七:基于业务规则自定义生成

根据具体应用场景的特点,可以考虑将某些业务属性(如用户ID、订单日期等)融入到主键ID的设计当中,以此降低并发冲突的可能性。

// 示例:结合时间戳与用户ID生成订单号
String orderId = String.format("%d_%s", System.currentTimeMillis(), userId);

优点:

  • 高度定制化,能满足特殊业务需求。
  • 减少了纯数字ID带来的单调感。

缺点:

  • 设计复杂度增加。
  • 可能会受到业务规则变化的影响。

方法八:Sharding-JDBC内置主键生成

最后值得一提的是,在使用Sharding-JDBC框架进行分库分表时,还可以选择其提供的内置主键生成策略(如UUID或Snowflake)。这种方式不仅简化了开发流程,而且能够更好地与其他组件集成。

sharding:
  tables:
    t_order:
      actual-data-nodes: ds${0..1}.t_order${0..1}
      table-strategy:
        inline:
          sharding-column: order_id
          algorithm-expression: t_order$->{order_id % 2}
      key-generator:
        type: SNOWFLAKE # 或者 UUID
        column: order_id

优点:

  • 无缝对接Sharding-JDBC生态体系。
  • 提供了多种成熟的主键生成算法供选择。

缺点:

  • 对非Sharding-JDBC用户来说不太友好。
  • 配置相对繁琐一些。

结论

综上所述,针对MySQL分库分表后的主键ID生成问题,我们有多种不同的解决方案可供选择。每种方法都有其独特之处,关键在于根据实际项目的需求做出最合适的决策。希望今天的分享能够帮助大家更加清晰地认识这个问题,并找到最适合自己的答案!如果你还有其他疑问或者更好的建议,请随时留言交流哦~ 😊

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号