【问题标题】:JOOQ - DataChangedException when calling Record.update()?JOOQ - 调用 Record.update() 时出现 DataChangedException?
【发布时间】:2018-04-16 22:24:58
【问题描述】:

我想我错过了关于 UpdatableRecord.update() 工作原理的重要内容。

不起作用的示例代码:

MailKeywordRealAddressRecord linkRecord = dsl.select().
  from(MAIL_KEYWORD_REAL_ADDRESS).
  where(MAIL_KEYWORD_REAL_ADDRESS.MAIL_KEYWORD_ID.eq(mailKeyword.getId())).
  fetchOneInto(MailKeywordRealAddressRecord.class);

if( linkRecord == null ){
  log.debug("no link record found for our mailKeyword");
  linkRecord = dsl.newRecord(MAIL_KEYWORD_REAL_ADDRESS);
  linkRecord.setMailKeywordId(mailKeyword.getId());
  linkRecord.setRealAddressId(realAddress.getId());

  linkRecord.insert();
}
else {
  // 1 - will geta "DataChangedException" because it tries to do a
  // "select ... for udpate" with the *new* realAddress id
  log.debug("updating old linkRecord from: {}", linkRecord );
  linkRecord.setRealAddressId(realAddress.getId());
  linkRecord.update();

  // 2 - working
  //      log.debug("updating old linkRecord from: {}", linkRecord );
  //      linkRecord.delete();
  //      linkRecord.setRealAddressId(realAddress.getId());
  //      linkRecord.insert();
}

这将导致异常:

DataChangedException: 数据库记录不再存在

如果我查看 SQL,JOOQ 正在使用 RealAddressId 的 new 值发出 select for update SQL 语句。

如果我注释掉 (1) 块并使用 (2) - JOOQ 似乎做了我想做的事,它会删除旧记录并更新新记录。

MailKeywordRealAddressRecord 下面的表是一个普通的多对多链接表(两列,都被声明为复合主键)。

考虑一下... - 是这个问题吗?我正在更新主键列? 我很高兴坚持删除/插入逻辑(或者我可以重构为直接的 SQL 语句)——只是想弄清楚发生了什么。

数据库是 Postgres,JOOQ 版本是 3.10.1。

【问题讨论】:

  • 您在使用Settings.executeWithOptimisticLockingIncludeUnversioned 功能吗?当您启用该功能时,您的期望是什么?
  • @LukasEder JOOQ 代码生成设置可以在这里找到:bitbucket.org/snippets/shorn/64RnL5/jooq-subproject 在我的 Spring 设置中,JOOQ 设置配置为“withExecuteWithOptimisticLocking(true)”。
  • 就我对该功能的期望而言 - 我不会认为它与没有版本字段的记录相关。
  • 嗯,该功能确实是说:“使用乐观锁定执行,包括那些没有版本字段的记录”。我会提供答案。

标签: java sql jooq


【解决方案1】:

一般建议:使用INSERT .. ON CONFLICT

您当前的逻辑可能会遇到竞争条件,并且通常写起来有点乏味。 jOOQ 支持 PostgreSQL 的 INSERT .. ON CONFLICT DO UPDATE 语法,它将对 upsert 的处理委托给数据库,您通常应该更喜欢这种方式,除非您真的依赖乐观锁定,而您在当前的代码示例中似乎没有这样做

回答您的问题

我认为这只是对 jOOQ 的乐观锁定功能的误解,另请参阅手册:

控制 jOOQ 乐观锁定特性的行为有两个设置:

  • executeWithOptimisticLocking:这允许完全关闭该功能。
  • executeWithOptimisticLockingExcludeUnversioned:这允许关闭未明确版本化的可更新记录的功能。

出于向后兼容的原因,默认情况下这两个标志都是关闭的。如果您打开乐观锁定,那么默认情况下,对于未明确配置版本字段的UpdatableRecords 也会打开它。在这种情况下,在执行乐观锁定检查时会验证整个记录。这可能不是您想要的,因此您应该将此标志设置为true

【讨论】:

    猜你喜欢
    • 2020-10-02
    • 2020-02-21
    • 2020-01-04
    • 2017-02-05
    • 2018-01-02
    • 1970-01-01
    • 2016-03-03
    • 2018-11-22
    • 2020-02-14
    相关资源
    最近更新 更多