生成将在 INSERT 语句中立即使用的 ID 号的最佳、独立于 DBMS 的方法是什么,使 ID 大致按顺序排列?
11 回答
DBMS 独立?那是个问题。两种最常见的方法是自动递增列和序列,大多数 DBMS 只做其中之一,但不会同时做这两个。因此,独立于数据库的方法是让另一个表具有一个具有一个值的列,您可以锁定、选择、更新和解锁。
通常我会说“与 DBMS 无关”,并使用 PostgreSQL 中的序列或 MySQL 中的自动增量列来做到这一点。就我的目的而言,支持两者都比试图找出一种适用于任何地方的方法要好。
如果您可以使用您选择的编程语言创建全局唯一标识符(GUID) - 将其视为您的 id。
在进行故障排除时,它们更难使用(输入where
INT 条件要容易得多),但也有一些优点。通过在本地将 GUID 分配为您的键,您可以轻松地建立父子记录关系,而无需先将父级保存到数据库并检索 id。并且由于 GUID,根据定义,是唯一的,您不必担心增加服务器上的密钥。
有自动递增或顺序
这有什么意义,这是你最不担心的?
您将如何处理 SQL 本身?MySQL有限制,
SQL Server 有顶级,
甲骨文有等级
然后还有一百万个其他的东西,比如触发器、改变表语法等
是的,原始 SQL 中的明显方法(以及我的偏好顺序)是 a) 序列 b) 自增字段。更好、更现代、更独立于 DBMS 的方法是根本不接触 SQL,而是使用(好的)ORM。
没有通用的方法可以做到这一点。如果有,每个人都会使用它。从定义上讲,SQL 厌恶这个想法 - 它是基于集合的逻辑的反模式(尽管在许多实际情况下是有用的)。
您尝试从其他地方插入标识值的最大问题是当 SQL 语句涉及多条记录时,必须同时生成多个值。
如果您需要它,请将其作为您的选择要求的一部分,以便数据库与您的应用程序一起使用。任何严肃的 DBMS 产品都会提供自己的使用机制,并且很容易围绕 DML 中的差异进行编码。变化几乎都在 DDL 中。
我总是选择数据库特定的解决方案,但如果你真的必须这样做的通常方法是实现你自己的序列。您的 RDBMS 必须支持事务。
您创建一个包含 int 列的序列表并使用第一个数字作为种子,然后您的事务逻辑看起来像这样
开始交易 更新 tblSeq 设置 intID = intID + 1 从 tblSeq 中选择 @myID = intID 插入 tblData (intID, ...) 值 (@myID, ...) 结束交易
事务强制写锁,这样下一个排队的插入不能在记录插入到 tblData 之前更新 tblSeq 值。只要所有插入都通过此事务,那么您生成的 ID 就是按顺序排列的。
使用自动递增的 id 列。
他们真的有理由必须按顺序排列吗?如果您只是将其用作 ID,那么您应该只能使用 UUID 的一部分或 md5(now()) 的前几个数字。
你可以花时间按摩它。它相当于类似的东西
DateTime.Now.Ticks
所以它就像 YYYYMMDDHHMMSSSS
它可能有点横向方法,但一个好的 ORM 类型库可能至少能够隐藏差异。例如,在 Ruby 中有 ActiveRecord(通常用于但不只与 Ruby the Rails Web 框架相关联),它具有迁移功能。在与平台无关的代码中声明的表定义中,数据类型、顺序 id 生成和索引创建等实现细节被推到您的视野之下。
我在 SQLite 上透明地开发了一个模式,然后在 MS SQL Server 上实现了它,后来移植到了 Oracle。无需更改生成我的架构定义的代码。
正如我所说,它可能不是您想要的,但封装变化的最简单方法是使用已经为您完成封装的库。
仅使用 SQL,以下可能是方法之一:
- 创建一个表以包含您需要的起始 id
- 首次部署应用程序时,应用程序应读取其上下文中的值。
- 此后,根据需要递增 id(以线程安全方式) 3.1 将 id 写入数据库(以线程安全方式)始终保持更新值 3.2 不要将其写入数据库,只需在内存中递增(线程- 安全的方式)
- 如果由于任何原因服务器出现故障,请将当前 id 值写入数据库
- 当服务器再次启动时,它将从上次离开的位置进行选择。