JDBC Lock Registry

版本 4.3 引入了 JdbcLockRegistry。某些组件(例如,聚合器和重新排序器)使用从 LockRegistry 实例获取的锁来确保一次只有一个线程操作一个组。DefaultLockRegistry 在单个组件中执行此功能。你现在可以在这些组件上配置外部锁注册表。与共享 MessageGroupStore 一起使用时,你可以使用 JdbcLockRegistry 为多个应用程序实例提供此功能,使得同一时间只有一个实例可以操作该组。

当本地线程释放锁后,另一个本地线程通常可以在立即获取锁。如果线程使用其他注册表实例释放锁,则获取锁可能需要长达 100 毫秒。

JdbcLockRegistry 基于 LockRepository 抽象,其有一个 DefaultLockRepository 实现。数据库模式脚本位于 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。如果要指定 ID 以与 DefaultLockRepository 关联,可将其指定为构造函数参数。

从 5.1.8 版开始,JdbcLockRegistry 可配置 idleBetweenTries - 在锁记录插入/更新执行之间休眠的 Duration。默认情况下,它是 100 毫秒,并且在某些环境中,非领导者会频繁使用数据源污染连接。

从5.4版本开始,引入了`RenewableLockRegistry`接口并将其添加到`JdbcLockRegistry`中。在锁定过程可能比锁定生命周期的生存时间更长的情况下,必须在锁定过程中调用`renewLock()`方法。因此,生存时间可以大大减少,并且部署可以快速地重新获得丢失的锁。

锁定续订只能在当前线程持有锁时执行。

从5.5.6版开始,`JdbcLockRegistry`通过`JdbcLockRegistry.setCacheCapacity()`自动清理`JdbcLockRegistry.locks`中的JdbcLock的缓存。有关更多信息,请参阅其JavaDoc文档。

从 6.0 版本开始,可以向 DefaultLockRepository 提供 PlatformTransactionManager,而不是依赖于应用程序上下文中主要的 bean。

从 6.1 版本开始,DefaultLockRepository 可针对自定义的 insertupdaterenew 查询进行配置。为此目的,公开各自的 setter 和 getter 方法。例如,可以这样配置 PostgreSQL 提示的插入查询:

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