一尘不染

用随机数替换序列

sql

我想用自己定制的id生成器替换我在postgresql数据库中用于id的一些序列。生成器将生成一个随机数,最后带有一个校验位。所以这:

SELECT nextval('customers')

将被这样的东西代替:

SELECT get_new_rand_id('customer')

然后,该函数将返回一个数字值,例如:[1-9][0-9]{9}其中最后一位是校验和。

我担心的是:

  1. 我如何使事物原子化
  2. 我如何避免两次返回相同的ID(试图将其插入具有唯一约束的列中会被捕获,但是我认为这太晚了)
  3. 这是个好主意吗?

注意1 :我不想使用uuid,因为它可以与客户进行通信,并且10位数字比36字符的uuid更容易通信。

注意2 :该函数很少用调用,SELECT get_new_rand_id()而是在id列而不是上被指定为默认值nextval()

编辑 :好的,下面很好的讨论!以下是有关 原因的 一些解释:

  1. 那么,为什么我会用这种方式使事情变得过于复杂呢?目的是向客户隐藏主键。

我给每个新客户一个唯一的customerId(数据库中生成的序列号)。由于我要与客户沟通该号码,因此竞争对手要监视我的业务是一项相当简单的任务(还有其他具有相同属性的号码,例如发票编号和订单编号)。我想使这种监视更加困难(注意:不是不可能,而是更加困难)。

  1. 为什么要输入校验位?

在谈论隐藏序列号nr之前,我在ordernr中添加了一个校验位,因为在生产中的某些时候手指有些笨拙,而且我认为这是将来保留的好习惯。

在阅读讨论之后,我当然可以看到我的方法不是解决问题的最佳方法,但是我对解决问题没有其他好主意,所以请在这里帮助我。

  1. 我是否应该在我暴露给客户的ID上添加一个额外的列,并将序列号保留为主键?
  2. 如何生成ID以合理有效的方式进行公开?
  3. 校验位是否必要?

阅读 141

收藏
2021-03-17

共1个答案

一尘不染

为了从序列中生成唯一且具有随机外观的标识符,使用密码可能是一个好主意。由于它们的输出是双射的(输入和输出值之间存在一对一的映射)-与哈希不同,您
不会有任何冲突 。这意味着您的标识符不必像哈希一样长。

大多数加密密码都可以在64位或更大的块上运行,但是PostgreSQL Wiki上有一个示例PL /
pgSQL过程,用于“非加密”密码
功能,该功能适用​​于(32位)int类型。免责声明:我尚未尝试使用此功能。

要将其用于主键,请从Wiki页面运行CREATE FUNCTION调用,然后在 表上执行以下操作:

ALTER TABLE foo ALTER COLUMN foo_id SET DEFAULT pseudo_encrypt(nextval('foo_foo_id_seq')::int);

瞧!

pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> insert into foo (foo_id) values(default);
pg=> select * from foo;
  foo_id   
------------
 1241588087
 1500453386
 1755259484
(4 rows)
2021-03-17