首页 > 解决方案 > Spring Integration JDBC锁失败

问题描述

我不了解从 JdbcLockRegistry 获得的分布式锁的行为。

@Bean
public LockRepository lockRepository(DataSource datasource) {
    return new DefaultLockRepository(datasource);
}

@Bean
public LockRegistry lockRegistry(LockRepository repository) {
    return new JdbcLockRegistry(repository);
}

我的项目在 PostgreSQL 上运行,Spring Boot 版本是 2.2.2 这是演示用例:

@GetMapping("/isolate")
public String isolate() throws InterruptedException {
    Lock lock = registry.obtain("the-lock");
    if (lock.tryLock(10, TimeUnit.SECONDS)) {   // close
        try {
            Thread.sleep(30 * 1000L);
        } finally {
            lock.unlock();                      // open
        }
    } else {
        return "rejected";
    }
    return "acquired";
}

注意:该用例在使用 Hazelcast 分布式锁时有效。

观察到的行为是通过在第一个实例上调用 API 在数据库中适当地注册了第一个锁。然后,在 30 秒内,在另一个实例(其他端口)上请求第二个 on,它正在更新现有 int_lock 表的行(client_id 更改)而不是失败。所以第一个端点在 30 秒后交付(没有解锁失败),第二个端点在它自己的 30 秒后交付。不存在互斥。

这些是单次采集的日志:

Trying to acquire lock...
Executing prepared SQL update
Executing prepared SQL statement [DELETE FROM INT_LOCK WHERE REGION=? AND LOCK_KEY=? AND CREATED_DATE<?]
Executing prepared SQL update
Executing prepared SQL statement [UPDATE INT_LOCK SET CREATED_DATE=? WHERE REGION=? AND LOCK_KEY=? AND CLIENT_ID=?]
Executing prepared SQL update
Executing prepared SQL statement [INSERT INTO INT_LOCK (REGION, LOCK_KEY, CLIENT_ID, CREATED_DATE) VALUES (?, ?, ?, ?)]
Processing...
Executing prepared SQL update
Executing prepared SQL statement [DELETE FROM INT_LOCK WHERE REGION=? AND LOCK_KEY=? AND CLIENT_ID=?]

不过,获取过程从 DELETE 开始听起来很奇怪……我尝试为 DefaultLockRepository 设置一个常量客户端 ID,但没有改进。有没有人知道如何解决这个问题?感谢您的帮助。

标签: jdbclockingspring-integration

解决方案


好的。碰巧存储库的 TTL 默认为 10 秒,就像我在那个特定用例中的超时一样。所以锁显然在超时期限之前死亡(DELETE)。这是一个修复:

@Bean
public LockRepository lockRepository(DataSource datasource) {
    DefaultLockRepository repository = new DefaultLockRepository(datasource);
    repository.setTimeToLive(60 * 1000);
    return repository;
}

推荐阅读