JOOQ从表中获取记录并将其插入另一个表中

时间:2017-01-12 16:56:51

标签: java sql jooq

我想从一个表中选择所有字段,获取另一个表的记录,然后将记录插入该表中。但是,我收到一个错误,指出值为null。以下是相关的代码:

    // Fetch
    PersonDeactivatedRecord person = getContext().selectFrom(PERSON)
            .where(PERSON.ID.eq(id))
            .fetchOneInto(PersonDeactivatedRecord.class);

    // Insert
    person.setDeactivatedOn(new Timestamp(System.currentTimeMillis()));
    getContext().insertInto(PERSON_DEACTIVATED)
            .set(person)
            .execute();

person_deactivated表是person表的副本加上一列(deactivated_on)。我得到的错误是:

org.jooq.exception.DataAccessException: SQL [insert into "xxx"."person_deactivated" ("deactivated_on") values (cast(? as timestamp))]; ERROR: null value in column "id" violates not-null constraint
  Detail: Failing row contains (null, null, null, null, null, null, null, null, null, ...)

请注意,当我调试此代码时,我看到person对象已按预期完全填充。知道我在这里缺少什么吗?

1 个答案:

答案 0 :(得分:2)

InsertSetStep.set(Record)方法不会将整个person记录插入目标表中,而只考虑其值为“已更改”的字段。见Javadoc:

  

这与调用set(Map)并将参数记录视为Map<Field<?>, Object>相同,除了考虑Record.changed()标志以便仅更新更改的值。

所以,你有几种方法可以解决这个问题(当然,这里列出的不止一些):

1。将所有已更改的标志设置为true

这将是最简单的修复:

// Insert
person.setDeactivatedOn(new Timestamp(System.currentTimeMillis()));
person.changed(true); // Sets all flags to true
getContext().insertInto(PERSON_DEACTIVATED)
        .set(person)
        .execute();

2。写一个查询

此解决方案的优点是您只有一个查询,这意味着:

  1. 单个服务器往返(延迟较少)
  2. 更好的锁定语义(数据库知道你在做什么,因此竞争条件的可能性更小)
  3. 所以,你可以写:

    getContext()
        .insertInto(PERSON_DEACTIVATED)
        .columns(PERSON_DEACTIVATED.fields())
        .select(
            select(Arrays
               .stream(PERSON_DEACTIVATED.fields())
               .map(f -> f.equals(PERSON_DEACTIVATED.DEACTIVATED_ON)
                       ? currentTimestamp()
                       : PERSON.field(f))
               .collect(Collectors.toList()))
           .from(PERSON)
           .where(PERSON.ID.eq(id))
        )
        .execute();
    

    与往常一样,此答案假设您的代码中包含以下静态导入:

    import static org.jooq.impl.DSL.*;
    

    上述查询会将PERSON中的所有列插入PERSON_DEACTIVATED,但DEACTIVATED_ON列将替换为当前时间戳。