【发布时间】:2011-06-28 11:36:06
【问题描述】:
我真的很困惑……但首先,让我给你一个粗略的概述。
我在数据库中进行了一些重组,将 4 个表合并为两个。所有表都有简单的数字序列作为主键。这些表实际上成对非常(非常)相似。将它们一分为二的唯一原因是基于必须导入的历史数据。如果没有这种拆分,就会有很多冗余,而且从概念上讲这是有道理的。
现在,在对数据清理进行了大量工作之后,现在终于可以合并它们并简单地使用其中一个字段作为鉴别器。为了不那么抽象,这些表格包含公司。他们要么是当地居民,要么不是(这两个阶级)。它们可以通过邮政编码(鉴别器字段)轻松区分。这些表的维度是缓慢变化的(序列是代理键)。其他两个表包含附加到这些 SCD 的常规数据。因此,有 4 张桌子。 2个本地公司,2个非本地人。
这些表现在已经被简化和合并,所以我现在只有Company 和CompanyData。
为了安全起见,为了不丢失任何历史信息,我创建了两个带有新序列字段的新表。保留旧序列以防 10 年后我意识到出了问题;)
到目前为止一切顺利。
重组相当容易,重新连接正确的条目也很容易。接下来,我需要更新与该数据库接口的应用程序,这需要更多的工作,但仍然很容易。该应用程序在 PostgreSQL 9.0 数据库之上使用 EclipseLink 2.0 使用 JPA。
奇怪的部分来了:
当我尝试插入一个新公司时,我收到一个重复键错误,指出给定的 ID 已经存在。但这应该由序列对象处理......不是吗?
所以我做了一些挖掘工作。我可以验证后续惰性确实返回了带有 incrementing id 的重复键错误。这意味着,序列逻辑是好的。唯一的问题是当前值太低。所以调用 nextval(或任何 JPA 使用)将返回一个已经存在的 ID。
我在 JPA-Entity 中有以下内容:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "enterprise_id_seq")
@Column(name = "id", nullable = false)
private Integer id;
我的序列看起来像这样:
test_db=# \d enterprise_id_seq
Sequence "public.enterprise_id_seq"
Column | Type | Value
---------------+---------+---------------------
sequence_name | name | enterprise_id_seq
last_value | bigint | 19659
start_value | bigint | 1
increment_by | bigint | 1
max_value | bigint | 9223372036854775807
min_value | bigint | 1
cache_value | bigint | 1
log_cnt | bigint | 32
is_cycled | boolean | f
is_called | boolean | t
我得到的错误是:
[...]
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.1.v20100213-
r6600): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "enterprise_pkey"
Detail: Key (id)=(19611) already exists.
Error Code: 0
Call: INSERT INTO en...
[...]
如您所见,它尝试插入一个 ID 为 19611 的实体,但序列中的最后一个值为 19659。这显然是错误的。
我还尝试重新启动所有这些背后的应用程序服务器,以关闭所有打开的连接和会话。没有运气......我注意到的另一件事:该字段定义为Integer。应该是Long 吗?这将需要对代码进行相当多的更改,而我还没有时间解决这个问题。
由于我只落后 50 个条目,我可以简单地尝试运行插入 50 次,但我宁愿确切知道出了什么问题...
我在这里错过了什么?
更新: 经过一番挖掘,我发现allocationSize 的默认值为 50。有趣的是,这与我看到的 ID 差异非常接近。由于一些测试和摩擦,它可能不是 100% 相同的。会不会有关系?老实说,我还没有理解这个设置背后的想法......
【问题讨论】:
-
会不会是旧的映射使用了不同的序列,而一个序列“落后于”另一个?另一个问题:您是否从另一个环境中复制了该数据?因为您可以在不复制序列的情况下迁移所有表。
-
您好 Augusto,感谢您的快速回复。首先,数据相同。它不是来自不同的环境。我只是重新排列并删除了一些表。另外,我不认为映射使用了不同的序列。新序列是具有全新专用序列的全新列。 -- 附带说明:我刚刚遇到了
allocationSize设置,它有趣地接近于我所说的“大约落后 50”。会不会有关系?
标签: java postgresql jpa eclipselink