JDBC Lock 登錄檔

4.3 版本引入了 `JdbcLockRegistry`。某些元件(例如,聚合器和重排序器)使用從 `LockRegistry` 例項獲取的鎖來確保一次只有一個執行緒操作一個組。`DefaultLockRegistry` 在單個元件內部執行此功能。現在你可以在這些元件上配置外部鎖登錄檔。與共享的 `MessageGroupStore` 一起使用時,可以使用 `JdbcLockRegistry` 在多個應用程式例項之間提供此功能,從而確保一次只有一個例項可以操作該組。

當鎖由本地執行緒釋放時,另一個本地執行緒通常可以立即獲取鎖。如果鎖由使用不同登錄檔例項的執行緒釋放,則可能需要長達 100 毫秒才能獲取鎖。

`JdbcLockRegistry` 基於 `LockRepository` 抽象,它有一個 `DefaultLockRepository` 實現。資料庫 schema 指令碼位於 `org.springframework.integration.jdbc` 包中,該包針對特定的 RDBMS 供應商進行了劃分。例如,以下清單顯示了鎖定表的 H2 DDL

CREATE TABLE INT_LOCK  (
    LOCK_KEY CHAR(36),
    REGION VARCHAR(100),
    CLIENT_ID CHAR(36),
    CREATED_DATE TIMESTAMP NOT NULL,
    constraint INT_LOCK_PK primary key (LOCK_KEY, REGION)
);

`INT_` 可以根據目標資料庫設計要求進行更改。因此,你必須在 `DefaultLockRepository` bean 定義上使用 `prefix` 屬性。

有時,某個應用程式會進入無法釋放分散式鎖並刪除資料庫中特定記錄的狀態。為此,此類死鎖可以在下次鎖定呼叫時由其他應用程式過期。`DefaultLockRepository` 上的 `timeToLive` (TTL) 選項就是為此目的提供的。你可能還想為給定 `DefaultLockRepository` 例項儲存的鎖指定 `CLIENT_ID`。如果是這樣,你可以將與 `DefaultLockRepository` 關聯的 `id` 指定為建構函式引數。

從 5.1.8 版本開始,`JdbcLockRegistry` 可以透過 `idleBetweenTries` 進行配置,它是一個 `Duration`,用於在鎖定記錄插入/更新執行之間休眠。預設情況下,它為 `100` 毫秒,在某些環境中,非領導者過於頻繁地汙染資料來源連線。

從 5.4 版本開始,引入了 `RenewableLockRegistry` 介面並將其新增到 `JdbcLockRegistry` 中。如果鎖定的過程比鎖的生存時間更長,則必須在鎖定過程中呼叫 `renewLock()` 方法。這樣可以大大減少生存時間,並且部署可以快速重新獲得丟失的鎖。

只有當前執行緒持有鎖時,才能進行鎖續期。

從 5.5.6 版本開始,`JdbcLockRegistry` 支援透過 `JdbcLockRegistry.setCacheCapacity()` 自動清理 `JdbcLockRegistry.locks` 中 JdbcLock 的快取。有關更多資訊,請參閱其 JavaDocs。

從 6.0 版本開始,可以為 `DefaultLockRepository` 提供一個 `PlatformTransactionManager`,而不是依賴於應用程式上下文中的主 bean。

從 6.1 版本開始,可以為 `DefaultLockRepository` 配置自定義的 `insert`、`update` 和 `renew` 查詢。為此,公開了相應的 setter 和 getter 方法。例如,可以這樣配置 PostgreSQL 提示的插入查詢

lockRepository.setInsertQuery(lockRepository.getInsertQuery() + " ON CONFLICT DO NOTHING");

從 6.4 版本開始,`LockRepository.delete()` 方法返回移除分散式鎖所有權的結果。並且如果鎖的所有權已過期,`JdbcLockRegistry.JdbcLock.unlock()` 方法會丟擲 `ConcurrentModificationException`。