Spring集成JDBC锁故障
我不理解从JdbcLockRegistry获得的分布式锁的行为Spring集成JDBC锁故障,jdbc,locking,spring-integration,Jdbc,Locking,Spring Integration,我不理解从JdbcLockRegistry获得的分布式锁的行为 @Bean public LockRepository lockRepository(DataSource datasource) { return new DefaultLockRepository(datasource); } @Bean public LockRegistry lockRegistry(LockRepository repository) { return new JdbcLockRegist
@Bean
public LockRepository lockRepository(DataSource datasource) {
return new DefaultLockRepository(datasource);
}
@Bean
public LockRegistry lockRegistry(LockRepository repository) {
return new JdbcLockRegistry(repository);
}
我的项目运行在PostgreSQL上,Spring启动版本是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秒内,在另一个实例(其他端口)上请求第二次打开,它将更新现有的int_锁表的行(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=?]
正在尝试获取锁。。。
执行准备好的SQL更新
执行准备好的SQL语句[DELETE FROM INT_LOCK WHERE REGION=?AND LOCK_KEY=?并创建了_DATE。碰巧存储库的TTL默认为10秒,就像我在特定用例中的超时一样。因此,锁显然在超时时间之前死亡(删除)。
下面是一个解决方案:
@Bean
public LockRepository lockRepository(DataSource datasource) {
DefaultLockRepository repository = new DefaultLockRepository(datasource);
repository.setTimeToLive(60 * 1000);
return repository;
}
为了维护一个锁,我尝试利用DefaultLockRepository#acquire(由lock#lock调用),它在插入新锁之前(以及在清除过期锁之后,如前所述)尝试更新:
@GetMapping(“/isolate”)
公共字符串隔离()引发InterruptedException{
Lock=registry.get(“锁”);
log.warn(“试图获取锁…”);
if(lock.tryLock(10,TimeUnit.SECONDS)){//关闭锁
试一试{
对于(inti=0;i<6;i++){//非常。。。
log.warn(“正在处理…”);
线程。睡眠(5*1000L);/…长任务
lock.lock();//调试保持(锁更新)
}
}最后{
如果(!repository.isAcquired(“锁”)){
抛出新的非法状态异常(“锁丢失”);
}否则{
lock.unlock();//打开锁
}
}
}否则{
返回“拒绝”;
}
返回“已获得”;
}
但这并没有像预期的那样起作用(注意:在本测试中,ttl默认为10秒);
尽管我可以在PostgreSQL的控制台中看到锁定日期的变化,但最终我总是会收到一个lock lost IllegalStateException异常。是的!这正是答案。在HazelcastleaseTimeout
的情况下,默认情况下太长了-long。最大值
。根据记录,我尝试在使用reposit解锁之前检测租约丢失ory.isAcquired(“锁”),但由于此函数在操作前清理超时锁(!!)这没有帮助,这是对的,因为TTL
比所有其他功能都有更高的优先级。@ArtemBilan明白。那么,我如何检测自己的锁丢失呢?是否有一个过程可以确保我将锁保持在很长的过程中,可能是通过定期重新获取它?Thx提前我只会使TTL太长。锁是g即使是应用程序停止,仍然需要解锁。
@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";
}