数据库主键的生成和处理

30 7月

数据库主键的作用是唯一标识一条记录,所以在同一张表中,任意一条记录的主键都是唯一的。如果没有唯一的主键,数据库就无法根据主键直接定位记录。

在各种流行的数据库中都存在主键这个概念,一般在建表的时候就需要指定主键,不过不同的数据库有不同语法而已

MySQL

CREATE TABLE People
(
 Id_P int NOT NULL,
 PRIMARY KEY (Id_P)
)

Oracle

CREATE TABLE People
(
  Id_P int NOT NULL PRIMARY KEY
)

对于数据库来说,主键是可以修改的,只要不和保证唯一性即可。但是对于一般应用来说修改主键通常会引起很多问题。比如表A的主键,作为外键在表B中。

主键策略

主键的使用可以考虑两个大方向:整数或者字符串。

先来看看整数,无非两个选项

  • 数据库自增
  • 自己生成

数据库自增是数据库提供的功能,稳定性可靠性高,自增主键的主要问题是在于把公司业务的关键运营数据完全暴露给了外部,可能导致信息泄露或者潜在的攻击。

虽然相关配置是可以变更的,比如MySQL可以自定义auto_increment_offset和auto_increment_increment,但是这个始终治标不治本。

自己生成的话常见的算法有Snowflake,美团开源的leaf也是容易上手的一个选项。

Snowflake算法是为了分布式ID生成的,用于数据库主键对于唯一性的保证不难,且本身不想自增长ID那么容易暴露业务信息。

如果使用字符串呢?

为了保证唯一性,最简单的手段就是UUID,当然字符串的随机性由于数据库索引的结构,可能影响插入性能。这个简单一点的方案就是在前面再加时间戳。GUID也是类似。

其他选择

如果一个已有业务,且是自增长主键应该怎么办?

如果没有分表分库此类需求,对于小量的业务,这里可以换一个思路。

在对外暴露主键的地方对ID做一个处理,最好是带盐的处理。hashId库就可以做到,它支持基本市面上所有常用语言,且支持自定义盐,可以很好的起到保护作用

Hashids hashids = new Hashids("mySalt");
String id = hashids.encode(1000011,1000012);
long[] numbers = hashids.decode(id);

参考

https://www.liaoxuefeng.com/article/1100985514586848

https://hashids.org/

发表评论

电子邮件地址不会被公开。