【问题标题】:Jooq- Updating a field to NULL makes it "null" and not NULLJooq-将字段更新为 NULL 使其“null”而不是 NULL
【发布时间】:2020-12-02 00:20:47
【问题描述】:

所以这是我之前在 jooq 3.11 中工作的查询。

我正在更新一个 JSON 字段,但是它使用 JsonBinding 映射到我的模型中的字符串,我将在下面发布

        dsl.update(TASK)
            .set(TASK.JSON_SOLUTION, (String) null).            
        .where(TASK.TENANT.eq(getCurrentTenant()))
        .and(TASK.TASK_TEMPLATE_ID.in(taskTemplateIds));execute()

升级到 jooq 3.13.2 后,此功能现在不再有效。即使我正在使用 mysql 5_7 数据库,我也必须将我的 sql 方言更改为 mysql,这可能是问题吗?

这个我也试过了,还是一样

        dsl.update(TASK)
            .setNull(TASK.JSON_SOLUTION).            
         .where(TASK.TENANT.eq(getCurrentTenant()))
        .and(TASK.TASK_TEMPLATE_ID.in(taskTemplateIds));execute()

JsonBinding.class

public class JsonBinding implements Binding<JSON, String> {

  @Override
  public Converter<JSON, String> converter() {
    return new JsonConverter();
  }

  @Override
  public void sql(BindingSQLContext<String> bindingSQLContext) {
    if (bindingSQLContext.render().paramType() == ParamType.INLINED) {
      bindingSQLContext
          .render()
          .visit(DSL.inline(bindingSQLContext.convert(converter()).value()))
          .sql("::json");
    } else {
      bindingSQLContext.render().sql("?");
    }
  }

  @Override
  public void register(BindingRegisterContext<String> bindingRegisterContext) throws SQLException {
    bindingRegisterContext
        .statement()
        .registerOutParameter(bindingRegisterContext.index(), Types.VARCHAR);
  }

  @Override
  public void set(BindingSetStatementContext<String> bindingSetStatementContext)
      throws SQLException {
    bindingSetStatementContext
        .statement()
        .setString(
            bindingSetStatementContext.index(),
            Objects.toString(bindingSetStatementContext.convert(converter()).value(), null));
  }

  @Override
  public void set(BindingSetSQLOutputContext<String> bindingSetSQLOutputContext)
      throws SQLException {
    throw new SQLFeatureNotSupportedException();
  }

  @Override
  public void get(BindingGetResultSetContext<String> bindingGetResultSetContext)
      throws SQLException {
    bindingGetResultSetContext
        .convert(converter())
        .value(
            JSON.valueOf(
                bindingGetResultSetContext
                    .resultSet()
                    .getString(bindingGetResultSetContext.index())));
  }

  @Override
  public void get(BindingGetStatementContext<String> bindingGetStatementContext)
      throws SQLException {
    bindingGetStatementContext
        .convert(converter())
        .value(
            JSON.valueOf(
                bindingGetStatementContext
                    .statement()
                    .getString(bindingGetStatementContext.index())));
  }

  @Override
  public void get(BindingGetSQLInputContext<String> bindingGetSQLInputContext) throws SQLException {
    throw new SQLFeatureNotSupportedException();
  }
}

JsonConverter.class

public class JsonConverter implements Converter<JSON, String> {

  @Override
  public String from(JSON object) {
    return object != null ? object.toString() : null;
  }

  @Override
  public JSON to(String string) {
    return JSON.valueOf(string);
  }

  @Override
  public Class<JSON> fromType() {
    return JSON.class;
  }

  @Override
  public Class<String> toType() {
    return String.class;
  }
}

这里是 jooq 使用 .setNull() 运行的查询

update `tasks_service`.`task` set `tasks_service`.`task`.`json_solution` = 'null'::json where (`tasks_service`.`task`.`tenant` = 'skynet' and `tasks_service`.`task`.`task_template_id` in ('55', '33'))

在 jooq 3.11 升级之前,查询是这样的

update `tasks_service`.`task` set `tasks_service`.`task`.`json_solution` = null::json where (`tasks_service`.`task`.`tenant` = 'skynet' and `tasks_service`.`task`.`task_template_id` in ('55', '33'))

所以在它设置 'json_solution' = null 之前和升级之后它似乎设置为 'json_solution' = 'null'

不太清楚为什么会这样?

编辑:所以据我所知,这似乎仅来自 JOOQ 的升级,而不是 sql 方言。使用带有 mysql 和 mysql_5_7 作为方言的 Jooq 3.11.5,查询构建为 set 'json_solution' = null,如果我将 JOOQ 升级到 3.13.2 它的 set 'json_solution' = 'null'

这个怪癖似乎也只发生在 JSON 字段上,我尝试在同一张表上将另一个 varchar String 字段设置为 null,我得到了正确的 set "field_name' = null

问题可能出在我的 JsonBinding/JsonConverter 上?我不得不稍微修改它以使用 JOOQ 中的新 JSON 对象,因为之前 JOOQ 将 JSON 映射为对象

【问题讨论】:

  • 执行的SQL是什么样子的?
  • 用查询更新了 OP

标签: jooq


【解决方案1】:

JSON.valueOf(null)(JSON) null

答案在org.jooq.JSON的Javadoc中:

CAST(NULL AS JSON) 值由JSON 类型的null 引用表示,而不是data() == null。这与 jOOQ 从ResultRecord 方法返回NULL 的一般方式一致。

所以,错误在于JsonConverterJSON.valueOf() 的使用。改为这样写:

  public JSON to(String string) {
    return string == null ? null : JSON.valueOf(string);
  }

或者,只需使用 Converter.ofNullable(),它会为您处理 null 到 null 的映射:

Converter<JSON, String> converter = Converter.ofNullable(
  JSON.class,
  String.class,
  JSON::data,
  JSON::json
);

关于使用Binding 的附注

你不再需要绑定了,现在 jOOQ 原生支持 JSON 类型。如果您想将JSON 转换为String,您的Converter 就足够了。

【讨论】:

  • 我做了第一个更改,我得到了查询更新tasks_service.task set tasks_service.task.task.json_solution = null::json where (tasks_service.@ 987654350@.tenant = 'skynet' 和 tasks_service.task.task_template_id in ('55', '33')) 2020-08-13 08:57:44.403 DEBUG 10058 --- [ main ] org.jooq.tools.LoggerListener:受影响的行:2
  • 但是在数据库中仍然设置为“null”而不是NULL
  • 我可以将查询复制并粘贴到我的数据库中,它可以按预期工作,但是 jooq 似乎将其设置为“null”
  • @HelloWhatsMyName1234:您观察到的差异是由于您正在复制粘贴调试日志输出,其中包含内联绑定值(您在其中显式转换为 json),而 jOOQ 执行准备好的声明。您还在使用自定义绑定吗?我没有检查它的全部,因为我以为你会放弃它。例如,我怀疑这是错误的:sql("?")。您需要将绑定值转换为 ?::json
  • 所以我确实有 ::json 就在绑定的上方。我将 if/else 语句部分都设置为 ?::json ,实际上我似乎得到了 Sql 语法异常。我将如何停止使用绑定并且仍然具有我现在使用的相同隐式行为?现在在我的生成器的 pom 中,我有以下内容
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-14
相关资源
最近更新 更多