当前位置: 首页 > 知识库问答 >
问题:

插入新的可更新记录并在重复的主键上接收错误

韦寒
2023-03-14

我试图在jOOQ 3.4.2中使用UpdateableRecords插入一个新记录。该模式非常简洁且易于使用,除了INSERT将空值读取为无值,并忽略默认值或生成的索引。我如何使用UpdateableRecord来执行一个尊重默认值和生成索引的插入?

这是我的桌子:

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 );

但是当我运行这个程序时,我会在“org\u person\u id”列中得到一个错误null值,该值违反了not null约束

我注意到jOOQ文档说,调用newRecord会自动将UpdateableRecord上的所有内部“更改”标志设置为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();

但这给了我一个错误:重复的键值违反了唯一约束“pk\u org\u person”。当我反复这么做时,这些值似乎一直在增加1。这对我来说没什么意义,但我更大的问题是:有没有一种好方法可以基于我的对象值进行插入,或者更好的方法是只包含非空列?

我看到JOOQ忽略了带有默认值的数据库列,但这似乎并不能解决这个问题。关于最简洁的处理方法有什么建议吗?

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

更新#1:

下面卢卡斯的回答解决了“非空问题”,这是一个简单的解决方法。

对于重复的主键,我绝对不会将INSERTUPDATE混淆。当我运行上述代码时(从最初的帖子开始有轻微的更新),jOOQ似乎会任意为OrgPersonId选择一个“开始”主键值。例如,当我第一次加载我的环境时,jOOQ可能以“11”开头表示OrgPersonId

然后,当我执行插入操作时,jOOQ将尝试为OrgPersonId提供一个值“11”,我将得到错误:重复键值,而插入操作将失败。如果我接着重复插入的,jOOQ使用“12”,然后是“13”。它的成功或失败取决于该ID是否可用,但它不是以正确的ID“开始”的。

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

更新#2:

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

更新#3:

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

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

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


共有1个答案

闽焕
2023-03-14

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

第二部分可能是由这样一个事实引起的,即您实际上正在加载一个现有的记录,然后在上面调用执行插入()(请注意INSERT,它将始终执行一个INSERT语句)。相反,您可能想要调用执行更新()

 类似资料:
  • 我目前使用JOOQ的可更新记录如下模式插入: 在,我希望使用数据库中的值更新,例如,如果表具有自动递增的列,将返回其值。 如果列具有唯一约束,则当违反该约束时,将抛出。我的问题是可以告诉JOOQ不要抛出异常,但仍然用现有的值更新记录吗?

  • 问题内容: 我有一张桌子,就是PK。当我插入行时,将有重复的键,并且我需要总结三个统计信息。我在Java中对PreparedStatement使用以下查询: 是否有更简洁的查询来实现?因为我简化了查询,所以那里有十多个统计信息。 问题答案:

  • 问题内容: 我正在执行插入查询,其中如果已经存在唯一键,则许多列中的大多数都需要更新为新值。它是这样的: 我不确定该子句的语法应该是什么。如何从子句引用当前行? 问题答案: MySQL将假定等号之前的部分引用INSERT INTO子句中命名的列,而第二部分引用SELECT列。

  • 问题内容: MySQL有这样的东西: 据我所知,SQLite中不存在此功能,我想知道的是,是否有任何方法可以实现相同的效果而不必执行两个查询。另外,如果这不可能,那么您更喜欢什么: SELECT +(插入或更新) 或 UPDATE( 如果UPDATE失败,则 + INSERT ) 问题答案: 因为3.24.0 SQLite还支持upsert ,所以现在您可以简单地编写以下内容

  • 这里一个非常常见的问题是如何执行upsert,MySQL称之为,标准支持将其作为操作的一部分。 鉴于PostgreSQL不直接支持它(在PG9.5之前),您如何做到这一点?考虑以下几点: 现在假设您要“upsert”元组,,那么新的表内容将是: 在Insert中,关于PostgreSQL中的重复更新?详细讨论了这个主题,但这是关于MySQL语法的替代方法,随着时间的推移,它增加了一些无关的细节。我

  • 好吧,问题不是关于如何返回ID,而是更像是如何跳过它...我有一种情况,我使用last_insert_id()获取最后插入行的id,但如果没有插入行,我想得到一个零。问题如下: < li >我插入...更新一些记录:由于这些行是新插入的,所以返回所有id < li >然后我重复该过程:这次不返回id。耶!这正是我想要的 < li >我更改了一个列值并重复该过程:但现在返回的是我更改了列值的行的ID