乐观锁定
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
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 字段的更多详细信息,请考虑手册中关于 高级代码生成器配置 的部分。
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!