跳到主要内容

JDBC 锁注册表

QWen Plus 中英对照 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)
);
sql

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");
java

从 6.4 版本开始,LockRepository.delete() 方法返回移除分布式锁所有权的结果。并且 JdbcLockRegistry.JdbcLock.unlock() 方法如果锁的所有权已过期,则会抛出 ConcurrentModificationException