2

我可以通过 JPA 或在数据库级别为数据库表主键设置一个 MAX 值吗?如果不可能,那么我在考虑

  1. key在 0-9999999999 之间创建一个随机数(9999999999 是我的 MAX)
  2. 使用新创建的数据库对数据库执行 SELECT key,如果返回对象是null,则 INSERT,如果不重复,则返回步骤 1

因此,如果我执行上述操作,有两个问题。请记住,环境是高并发的:

Q1:用 SELECT 检查的开销,如果不存在,INSERT 是否显着?我真正的意思是:这个过程是否正常,因为通常我让数据库为我创建一个独特的 PK?

Q2:如果 Q1 没有造成显着的性能下降,我会遇到并发问题吗?例如,如果 P1 用 Id1 查表,Id1 不存在,它准备插入,P2 在 P1 可以之前偷偷插入 Id1。所以当 P1 插入 Id1 时,它会失败。我不希望这个过程在这里失败,我希望它回到循环,找到一个新的 id,重复这个过程。我怎么做?

我的环境是 SQL 和 MYSQL db。我将 JPA 与 Eclipselink 实现一起使用

注意:有些人质疑我以这种方式实现它的决定,答案正是TravisJ下面的建议。我有一个非常高的并发环境。当一个进程启动时,我需要向另一个进程创建一个请求,向该进程传递一个唯一的 10 个字符长的 ID。由于环境是大电流,我想利用 PK 的独特而非空特性。请求中包含大量信息,因此我创建了一个Request表,请求 Id 作为我的 PK。我知道,由于所有数据库都索引他们的 PK,因此查询出 PK 的速度很快。如果有更好的方法,请告诉我。

4

3 回答 3

2

为什么不从 1 开始并使用自动增量?这将更有效率,因为您不会遇到必须循环通过的碰撞。如果你的数字用完了,无论哪种方式,你都会在同一条船上,但至少按顺序进行,你不必处理碰撞。

想象一下,当您用完 90% 的可用号码时,试图找到一个未使用的密钥。这将需要一些时间,并且如果您随机生成它们,它总是有可能(在您的一生中)永远找不到未使用的密钥。

此外,使用自动增量,很容易判断您是否接近极限 ( SELECT MAX(col))。您可以编写警报脚本,让您知道何时需要重置。对于随机方法,该查询会是什么样子?

如果您使用的是 InnoDB,那么您可能仍然不想使用主键。将随机记录插入聚集索引会影响性能,因为必须对实际表数据进行重新排序。而是使用唯一键(使用自动增量主键)。

在有问题的列上使用唯一索引,只需在范围内生成一个随机数并尝试插入它。如果插入失败,则生成一个新号码并重试。如果插入成功,则继续。这解决了并发问题。

尽管如此,顺序自动增量键将产生更好的性能。

于 2012-04-04T23:28:50.803 回答
2

您可以在表定义中实现检查约束:

CREATE TABLE P
(
P_Id int PRIMARY KEY NOT NULL,
...
CONSTRAINT chk_P_Id CHECK (P_Id>0 and P_Id<9999999999)
)

编辑:如评论中所述,MySql 不遵守 CHECK 约束。这是错误日志中存在 6 年的缺陷,MySql 团队尚未修复它。由于 MySql 现在由 Oracle 公司监管,它可能永远不会被修复(简单地认为是“记录的限制”,不喜欢它的人可以升级到付费 DBMS)。但是,这种语法和检查约束特性本身在 Oracle、MS SQL Server(包括 SQLExpress/MSDE)、MS Access、Postgre 和 SQLite 中都可以工作。

于 2012-04-04T21:00:04.123 回答
1

看,

http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing

和,

http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Advanced_Sequencing

JPA 已经有很好的 Id 生成支持,实现你自己的没有意义。

如果您关心并发性和性能,并且使用 MySQL,我建议您使用具有较大预分配大小的 TABLE 生成器(在其他数据库上,我建议使用 SEQUENCE 生成器)。如果您有大量数据,请确保使用 long 作为您的 id。

如果你真的认为你需要更多,那么考虑 UUID id 生成。EclipseLink 2.4 提供了一个@UUIDGenerator。

于 2012-04-05T13:35:47.650 回答