可用版本:Dev (3.21) | 最新 (3.20) | 3.19 | 3.18 | 3.17 | 3.16 | 3.15 | 3.14 | 3.13 | 3.12 | 3.11

乐观锁定

适用于 ✅ 开源版   ✅ 专业版   ✅ 企业版

jOOQ 允许您使用乐观锁执行 CRUD 操作。您可以通过激活相关的 executeWithOptimisticLocking 设置 立即利用此功能。在不了解底层数据语义的情况下,这将对 store() 和 delete() 方法产生以下影响

  • INSERT 语句不受此设置标志的影响
  • 在执行 UPDATE 或 DELETE 语句之前,jOOQ 将运行一个 SELECT .. FOR UPDATE 语句,以悲观方式锁定记录,以供后续的 UPDATE / DELETE 操作使用
  • 通过先前的 SELECT 获取的数据将与正在存储或删除的记录中的数据进行比较
  • 如果记录在此期间被修改或删除,或者如果乐观锁是在未从数据库获取的未版本化记录上执行的,则会抛出一个 org.jooq.exception.DataChangedException 异常。
  • 如果记录在此期间未被修改,则记录将成功存储/删除。

以上对 jOOQ 行为的更改对 API 是透明的,您要激活它的唯一方法是设置 Settings 标志。以下是一个说明乐观锁定的示例

// Properly configure the DSLContext
DSLContext optimistic = DSL.using(connection, SQLDialect.ORACLE,
  new Settings().withExecuteWithOptimisticLocking(true));

// Fetch a book two times
BookRecord book1 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));
BookRecord book2 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));

// Change the title and store this book. The underlying database record has not been modified, it can be safely updated.
book1.setTitle("Animal Farm");
book1.store();

// Book2 still references the original TITLE value, but the database holds a new value from book1.store().
// This store() will thus fail:
book2.setTitle("1984");
book2.store();

使用 TIMESTAMP 字段的优化乐观锁定

如果您正在使用 jOOQ 的 代码生成器,则可以在 代码生成配置中为每个生成的表指示 TIMESTAMP 或 UPDATE COUNTER 字段。假设我们有这个表

CREATE TABLE book (

  -- This column indicates when each book record was modified for the last time
  MODIFIED TIMESTAMP NOT NULL,
  -- [...]
)

MODIFIED 列将包含一个时间戳,指示 BOOK 表中任何图书的上次修改时间戳。如果您正在使用 jOOQ 及其 UpdatableRecords 上的 store() 方法,则 jOOQ 将自动为您生成此 TIMESTAMP 值。但是,jOOQ 不是在 UPDATE 或 DELETE 语句之前运行额外的 SELECT .. FOR UPDATE 语句,而是将 WHERE 子句添加到 UPDATE 或 DELETE 语句中,以检查 TIMESTAMP 的完整性。以下示例可以最好地说明这一点

// Properly configure the DSLContext
DSLContext optimistic = DSL.using(connection, SQLDialect.ORACLE,
  new Settings().withExecuteWithOptimisticLocking(true));

// Fetch a book two times
BookRecord book1 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));
BookRecord book2 = optimistic.fetchOne(BOOK, BOOK.ID.eq(5));

// Change the title and store this book. The MODIFIED value has not been changed since the book was fetched.
// It can be safely updated
book1.setTitle("Animal Farm");
book1.store();

// Book2 still references the original MODIFIED value, but the database holds a new value from book1.store().
// This store() will thus fail:
book2.setTitle("1984");
book2.store();

和以前一样,如果没有添加 TIMESTAMP 列,乐观锁定对 API 是透明的。

使用 VERSION 字段的优化乐观锁定

除了使用 TIMESTAMP 之外,您还可以使用数字 VERSION 字段,其中包含 jOOQ 在 store() 调用时递增的版本号。

请注意,对于显式悲观锁定,请考虑手册中关于 FOR UPDATE 子句 的部分。有关如何配置 TIMESTAMP 或 VERSION 字段的更多详细信息,请考虑手册中关于 高级代码生成器配置 的部分。

反馈

您对此页面有任何反馈吗? 我们很乐意听取您的意见!

The jOOQ Logo