跳到主要内容
版本:7.0.2

JDBC 锁注册表

DeepSeek V3 中英对照 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) NOT NULL,
REGION VARCHAR(100) NOT NULL,
CLIENT_ID CHAR(36),
CREATED_DATE TIMESTAMP NOT NULL,
EXPIRED_AFTER 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");

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

自 7.0 版本起,JdbcLock 实现了 DistributedLock 接口,以支持为锁状态数据自定义生存时间(TTL)的功能。现在可以使用 lock(Duration ttl)tryLock(long time, TimeUnit unit, Duration ttl) 方法获取 JdbcLock,并指定一个生存时间(TTL)值。JdbcLockRegistry 现在提供了新的 renewLock(Object lockKey, Duration ttl) 方法,允许您使用自定义的生存时间值来续期锁。现在可以通过新的构造函数 JdbcLockRegistry(LockRepository client, Duration expireAfter) 来设置存储在同一个 JdbcLockRegistry 中的所有 JdbcLock 实例的默认生存时间。LockRepositoryDefaultLockRepository 的 API 也进行了修改以支持此功能。

important

如果您正在使用早期版本的 JdbcLockRegistryDefaultLockRepository,请在升级到此版本之前执行必要的 DDL 来修改 INT_LOCK 表。

以下是为锁表添加新列的 Postgres DDL 示例:

ALTER TABLE INT_LOCK ADD EXPIRED_AFTER TIMESTAMP NOT NULL;