首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring Integration JDBC锁定失败

Spring Integration JDBC锁定失败
EN

Stack Overflow用户
提问于 2019-12-11 22:11:50
回答 2查看 2.2K关注 0票数 2

我不理解从JdbcLockRegistry获取的分布式锁的行为。

代码语言:javascript
复制
@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,这是演示用例:

代码语言:javascript
复制
@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秒后交付。没有相互排斥的关系。

以下是单个采集的日志:

代码语言:javascript
复制
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=?]

虽然听起来很奇怪,获取过程是从删除开始的。我已经尝试为DefaultLockRepository设置一个恒定的客户端id,但没有任何改进。有没有人知道如何解决这个问题?谢谢你的帮助。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-11 22:49:14

好的。默认情况下,存储库的TTL是10s,就像我在那个特定用例中的超时一样。所以锁显然在超时之前就死了(删除)。下面是一个解决方法:

代码语言:javascript
复制
@Bean
public LockRepository lockRepository(DataSource datasource) {
    DefaultLockRepository repository = new DefaultLockRepository(datasource);
    repository.setTimeToLive(60 * 1000);
    return repository;
}
票数 2
EN

Stack Overflow用户

发布于 2019-12-13 23:44:28

为了维护锁,我尝试利用Lock#lock调用的DefaultLockRepository#acquire,它在插入新锁之前(以及在清理过期锁之后,如前所述)尝试更新:

代码语言:javascript
复制
@GetMapping("/isolate")
public String isolate() throws InterruptedException {
    Lock lock = registry.obtain("the-lock");
    log.warn("Trying to acquire lock...");
    if (lock.tryLock(10, TimeUnit.SECONDS)) {    // close lock
        try {
            for (int i=0; i < 6; i++) {          // very...
                log.warn("Processing...");
                Thread.sleep(5 * 1000L);         // ... long task
                lock.lock();                     //DEBUG holding (lock update)
            }
        } finally {
            if (!repository.isAcquired("the-lock")) {
                throw new IllegalStateException("lock lost");
            } else {
                lock.unlock();                   // open lock
            }
        }
    } else {
        return "rejected";
    }
    return "acquired";
}

但这并没有像预期的那样工作(在这个测试中,ttl是默认的10秒);尽管我可以在PostgreSQL的控制台中看到锁定日期的变化,但我最终总是得到一个锁丢失的IllegalStateException。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59287676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档