我认为我错过了有关 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: Database record no longer exists
如果我查看 SQL,JOOQ 会使用 RealAddressId 的 new 值发出 select for update
SQL 语句。
如果我注释掉 (1) block 并使用 (2) - JOOQ 似乎可以执行我想要的操作,它会删除旧记录并更新新记录。
MailKeywordRealAddressRecord 下面的表是一个普通的多对多链接表(两列,均被声明为复合主键)。
想一想... - 这是问题所在吗?我正在更新主键列? 我很高兴坚持使用删除/插入逻辑(或者我可以重构为直接 SQL 语句) - 只是想弄清楚发生了什么。
数据库是Postgres,JOOQ版本是3.10.1。
最佳答案
一般建议:使用INSERT .. ON CONFLICT
您当前的逻辑可能会遇到竞争条件,并且通常编写起来有点乏味。 jOOQ 支持 PostgreSQL 的 INSERT .. ON CONFLICT DO UPDATE 语法,该语法将 upsert 的处理委托(delegate)给数据库,您通常应该更喜欢这种方式,除非您确实依赖于乐观锁定,而您在当前的代码示例中似乎没有这样做
回答您的问题
我认为这只是源于对 jOOQ 乐观锁定功能的误解,另请参阅手册:
- https://www.jooq.org/doc/latest/manual/sql-building/dsl-context/custom-settings/settings-optimistic-locking
- https://www.jooq.org/doc/latest/manual/sql-execution/crud-with-updatablerecords/optimistic-locking
There are two settings governing the behaviour of the jOOQ optimistic locking feature:
- executeWithOptimisticLocking: This allows for turning off the feature entirely.
- executeWithOptimisticLockingExcludeUnversioned: This allows for turning off the feature for updatable records who are not explicitly versioned.
出于向后兼容性的原因,默认情况下这两个标志均处于关闭状态。如果您打开乐观锁定,那么默认情况下,对于未显式配置版本字段的 UpdatableRecords
也会打开乐观锁定。在这种情况下,在执行乐观锁定检查时会验证整个记录。这可能不是您想要的,因此您应该将此标志设置为 true
。
关于java - JOOQ - 调用 Record.update() 时出现 DataChangedException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47108449/