|
如需使用最新稳定版本,请使用 Spring Integration 7.0.4! |
JDBC 锁注册表
版本 4.3 引入了 JdbcLockRegistry。
某些组件(例如聚合器和重排序器)使用从 LockRegistry 实例获取的锁,以确保同一时间只有一个线程操作一个组。
DefaultLockRegistry 在单个组件内执行此功能。
现在您可以为这些组件配置外部锁注册表。
当与共享的 MessageGroupStore 一起使用时,您可以使用 JdbcLockRegistry 在多个应用程序实例之间提供此功能,从而确保同一时间只有一个实例能够操作该组。
当锁由本地线程释放时,另一个本地线程通常可以立即获取该锁。 如果锁是由使用不同注册表实例的线程释放的,则获取该锁可能需要长达 100ms。
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 属性。
有时,一个应用程序会进入无法释放分布式锁并从数据库中移除特定记录的状态。
为此,其他应用程序可以在下一次加锁调用时使此类死锁过期。
timeToLive(TTL)选项在DefaultLockRepository上提供,正是用于此目的。
对于存储在给定DefaultLockRepository实例中的锁,您可能还希望指定CLIENT_ID。
如果是这样,您可以将id作为构造函数参数与DefaultLockRepository关联起来。
从版本 5.1.8 开始,JdbcLockRegistry 可以使用 idleBetweenTries 进行配置——这是一个在锁定记录插入/更新执行之间睡眠的 Duration。
默认情况下,它是 100 毫秒,并且在某些环境中,非领导者会过于频繁地通过数据源污染连接。
从版本 5.4 开始,已引入 RenewableLockRegistry 接口并将其添加到 JdbcLockRegistry 中。
在锁定过程可能超过锁的存活时间的情况下,必须在锁定过程中调用 renewLock() 方法。
因此,可以显著缩短锁的存活时间,部署操作也能更快地重新获取丢失的锁。
| 锁的续期操作仅当锁由当前线程持有时方可执行。 |
从版本 5.5.6 开始,JdbcLockRegistry 支持通过 JdbcLockRegistry.setCacheCapacity() 自动清理 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 异常。