java - 插入新的 UpdatableRecord 并在重复的主键上接收错误

标签 java sql postgresql jooq

我正在尝试使用 jOOQ 3.4.2 中的 UpdatableRecords 插入新记录。该模式非常简洁且易于使用,除了 INSERT 将 null 值读取为无值并忽略默认值或生成的索引。我如何使用 UpdatableRecord 执行符合默认值和生成索引的插入?

这是我的 table :

CREATE TABLE aragorn_sys.org_person (
    org_person_id SERIAL  NOT NULL,
    first_name CHARACTER VARYING(128)  NOT NULL,
    last_name CHARACTER VARYING(128)  NOT NULL,
    created_time TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp  NOT NULL,
    created_by_user_id INTEGER,
    last_modified_time TIMESTAMP WITH TIME ZONE,
    last_modified_by_user_id INTEGER,
    org_id INTEGER  NOT NULL,
    CONSTRAINT PK_org_person PRIMARY KEY (org_person_id)
);

记下我的主键和默认值。现在这是我的 jOOQ 代码:

// orgPerson represents a POJO filled with my values to be inserted and null for everything else
// Note that orgPerson.orgPersonId is null
OrgPersonRecord orgPersonRecord = create.newRecord( ORG_PERSON, orgPerson );
Integer orgPersonId = create.executeInsert( orgPersonRecord );

但是当我运行它时,我得到错误 null value in column "org_person_id"violates not-null constraint

我注意到 jOOQ 文档说调用 newRecord 会自动将 UpdatableRecord 上的所有内部“已更改”标志设置为 true。然后我尝试了这个:

// orgPerson represents a POJO filled with my values to be inserted and null for everything else
// Note that orgPerson.orgPersonId is null
OrgPersonRecord orgPersonRecord = create.newRecord( ORG_PERSON, orgPerson );
orgPersonRecord.changed( ORG_PERSON.ORG_PERSON_ID, false );
orgPersonRecord.changed( ORG_PERSON.CREATED_TIME, false );
orgPersonRecord.insert()
Integer orgPersonId = orgPersonRecord.getOrgPersonId();

但这给了我错误 ERROR: duplicate key value violates unique constraint "pk_org_person"。当我重复执行此操作时,值似乎一直增加 1。这对我来说真的没有意义,但我更大的问题是:是否有一种好方法可以根据我的对象值执行 INSERT ,或者更好的是,只包含非空列

我看到了JOOQ ignoring database columns with default values ,但这似乎并不能解决这个问题。关于处理此问题的最简洁方法的任何建议?

顺便说一句,到目前为止,与 jOOQ 的合作非常棒。 Lukas,谢谢你提供这个很棒的工具!

更新 #1:

Lukas 在下面的回答中解决了“not null 问题”,这很容易解决。

对于重复的主键,我绝对不会混淆 INSERTUPDATE。当我运行上面的代码时(自原始帖子以来略有更新),jOOQ 似乎任意选择 OrgPersonId 的“起始”主键值。例如,当我第一次加载我的环境时,对于 OrgPersonId,jOOQ 可能以“11”开头。

然后,当我执行 INSERT 时,jOOQ 将尝试为 OrgPersonId 提供值“11”,我将得到 ERROR: duplicate键值INSERT 将失败。如果我然后重复 INSERT,jOOQ 使用“12”,然后是“13”。它的成功或失败取决于该 ID 是否可用,但它不是以正确的 ID“开始”。

手册 ( http://www.jooq.org/doc/3.4/manual/sql-execution/crud-with-updatablerecords/identity-values/ ) 说 如果您使用 jOOQ 的代码生成器,上表将生成一个带有 IDENTITY 列的 org.jooq.UpdatableRecord。 jOOQ 在内部使用此信息,在调用 store() 后更新 ID

更新 #2:

好的,我刚刚在 Postgres 中直接尝试了生成的查询,但它也失败了,并出现了同样的问题。所以,很明显这是一个 Postgres 问题而不是 jOOQ 问题。当我找到它时,我会发布最终解决方案,以防其他人遇到这个问题。

更新 #3:

问题已解决。我们使用 FlywayDB(另一个很棒的工具)来自动化我们的数据库模式迁移,并且我们在我们的 Flyway 脚本中有一堆 INSERT 语句手动插入 ID 号。这很方便,因为我们想创建一堆虚拟数据并想保证正确的外键关系。

但是手动指定主键增量不会推进 Postgres 序列!因此,我们必须在(正确操作)jOOQ 获得正确的序列值之前循环遍历 Postgres 序列。

解决方案是删除我们在演示数据迁移脚本中手动插入的所有主键。

最佳答案

违反非空约束

您描述的第一部分是一个缺陷 ( #3582 ),它与之前的问题 ( #2700 ) 有关,它强制将从 POJO 加载的 null 值存储到 jOOQ 中Records 用于 NOT NULL 的数据库列。修复将在 jOOQ 3.5.0、3.4.3、3.3.4 和 3.2.7 中

重复键值违反唯一约束“pk_org_person”

第二部分可能是由于您实际上是在加载现有记录然后调用 executeInsert() 造成的。在它上面(观察 INSERT,它将始终执行 INSERT 语句)。您可能想调用 executeUpdate() , 而不是

关于java - 插入新的 UpdatableRecord 并在重复的主键上接收错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25399183/

相关文章:

java - JTable 多行单元格自动换行

PostgreSQL 中相邻模型的 SQL 查询

postgresql - 将表从 Postgres 导入 Arcmap

postgresql - 错误 : type "public.geometry" does not exist

java - 接口(interface)中的协变返回类型未通过 Javac 编译

java - 如何清除 Java 中的控制台 - Eclipse

Java重力循环优化

mysql - 合并表而不是相交

sql - ROLLBACK TRAN 会回滚所有内容吗?

mysql - SQL更新执行顺序有关系吗?