JDBC 锁注册表

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。如果是这样,您可以将要与 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 可以配置用于自定义 insertupdaterenew 查询。为此,公开了相应的 setter 和 getter。例如,可以像这样配置 PostgreSQL 提示的插入查询

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