jOOQ转换器在写入记录时隐式设置一个值

jOOQ converter implicitly set a value when writing a record

在我的 postgresql 数据库的 table 中,我有 2 个具有默认值的列。

我在 jOOQ 生成器配置中为其中之一定义了一个转换器。

当我执行函数 record.store() 时,默认值适用于没有转换器的字段,但不适用于另一个变为空的字段。

我从未明确设置这些字段,但我猜想 record.changed(MY_OBJECT.FIELD) == true 在转换器执行后。

我不确定这是预期的行为。这是一个错误吗?有解决方法吗?

编辑:这是使用的代码

TimestampBinding.java

public class TimestampBinding implements Binding<Timestamp, Instant> {

    private static final Converter<Timestamp, Instant> converter = new TimestampConverter();

    private final DefaultBinding<Timestamp, Instant> delegate = new DefaultBinding<> (converter());

    @Override
    public Converter<Timestamp, Instant> converter() { return converter; }

    @Override
    public void sql(BindingSQLContext<Instant> ctx) throws SQLException {
        delegate.sql(ctx);
    }

    @Override
    public void register(BindingRegisterContext<Instant> ctx) throws SQLException {
        delegate.register(ctx);
    }

    @Override
    public void set(BindingSetStatementContext<Instant> ctx) throws SQLException {
        delegate.set(ctx);
    }

    @Override
    public void set(BindingSetSQLOutputContext<Instant> ctx) throws SQLException {
        delegate.set(ctx);
    }

    @Override
    public void get(BindingGetResultSetContext<Instant> ctx) throws SQLException {
        delegate.get(ctx);
    }

    @Override
    public void get(BindingGetStatementContext<Instant> ctx) throws SQLException {
        delegate.get(ctx);
    }

    @Override
    public void get(BindingGetSQLInputContext<Instant> ctx) throws SQLException {
        delegate.get(ctx);
    }
}

TimestampConverter.java

public class TimestampConverter implements Converter<Timestamp, Instant> {
    @Override
    public Instant from(Timestamp ts) {
        return ts == null ? null : ts.toInstant();
    }
    @Override
    public Timestamp to(Instant instant) {
        return instant == null ? null : Timestamp.from(instant);
    }
    @Override
    public Class<Timestamp> fromType() { return Timestamp.class; }
    @Override
    public Class<Instant> toType() { return Instant.class; }
}

sql

CREATE TABLE user (
  id uuid PRIMARY KEY,
  active boolean NOT NULL DEFAULT false,
  created_at timestamptz DEFAULT now()
);

店铺记录

user.setId(UUID.randomUUID());
UserRecord userRecord = DSL.using(conn, SQLDialect.POSTGRES_9_3)
                .newRecord(userTable.USER, user);
userRecord.store();

这种行为是 "expected" 并且在 jOOQ 中有很长的历史。简短的解释在这里:

  • 您的列 activeNOT NULL,因此 Java 值 null 被解释为 SQL 值 DEFAULT,无论Record.changed() 标志。
  • 您的列 created_at 可以为空,因此 Java 值 null 被解释
    • 作为 SQL 值 DEFAULT if Record.changed(CREATED_AT) == false
    • 作为 SQL 值 NULL if Record.changed(CREATED_AT) == true

通过调用 DSLContext.newRecord(),您正在将 user POJO 中的所有值复制到 userRecord,包括所有 null 值。 jOOQ 无法区分 null 未初始化的值和 null 明确的值... null.

在您的特定情况下,最好的解决方案是声明所有列 NOT NULL(无论如何在概念层面上更好):

CREATE TABLE user (
  id uuid PRIMARY KEY,
  active boolean NOT NULL DEFAULT false,
  created_at timestamptz NOT NULL DEFAULT now()
);