You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.2.4 JDBC分布式锁失效问题排查求助

问题分析与修复方案

1. 锁Key生成错误(最可能导致锁失效的核心原因)

你的getKey方法存在两处致命问题:

  • 变量拼写错误:方法参数是request,但代码中使用了未定义的req,这会导致编译错误或生成完全错误的锁Key值。
  • 业务维度错误:你用request.getNumber()生成锁Key,但从日志逻辑来看,需要防止重复创建的是同一orderId的订单。如果request.getNumber()不是订单的唯一标识(比如是请求流水号或未生成的订单号),不同请求会生成不同的锁Key,锁机制完全起不到作用。

修复代码:
修正变量拼写,并基于订单ID生成锁Key:

private static String getKey(AbstractOrderRequest request) {
    return "ORDER_ID_%s".formatted(request.getOrderId());
}

2. tryLock参数概念误用

你把锁存活时间(lockTimeToLive)传给了tryLock的等待超时参数,完全混淆了两个概念:

  • tryLock(long timeout, TimeUnit unit)的作用是:当前线程最多等待timeout时间尝试获取锁,超时则返回false。
  • 锁的存活时间是JdbcLockRegistry的配置参数,用于防止持有锁的实例宕机后锁永久占用。

修复配置:
单独配置等待超时时间,同时在JdbcLockRegistry中指定锁存活时间:

@Bean
public LockRegistry lockRegistry(DataSource dataSource) {
    // 锁存活时间设为5秒(5000毫秒),需大于请求实际执行时长
    return new JdbcLockRegistry(dataSource, "INT_LOCK", 5000);
}

3. 错误的锁释放逻辑

无论是否成功获取锁,你都在finally块中调用unlock(),这会导致:

  • 未拿到锁的线程执行无效释放操作,可能干扰锁的状态管理。
  • 日志出现误导性的"Unlocking lock"信息,增加排查难度。

修复代码:
仅在成功获取锁后才执行释放操作:

@Override
public T lockAndExecute(String key, Callable<T> runnable) throws Exception {
    log.info("Trying to obtain lock for key: {}", key);
    Lock lock = lockRegistry.obtain(key);
    boolean isLocked = false;
    try {
        // 这里的参数是等待锁的超时时间,可根据业务需求单独配置
        isLocked = lock.tryLock(3, TimeUnit.SECONDS);
        if (isLocked) {
            log.info("Obtained lock for key: {}", key);
            return runnable.call();
        }
    } catch (Exception e) {
        log.error("Exception occurred while trying to get lock and execute", e);
        throw e;
    } finally {
        if (isLocked) {
            log.info("Unlocking lock for key: {}", key);
            lock.unlock();
        }
    }
    return null;
}

4. 数据库锁表配置验证

确保两个服务实例使用同一个Postgres数据库,且INT_LOCK表已正确创建(Postgres SQL语句):

CREATE TABLE INT_LOCK (
    LOCK_KEY VARCHAR(255) NOT NULL PRIMARY KEY,
    REGION VARCHAR(255) NOT NULL,
    CLIENT_ID VARCHAR(255) NOT NULL,
    CREATED_DATE TIMESTAMP NOT NULL
);

若两个实例配置的锁表名称不同,分布式锁机制会完全失效。

内容的提问来源于stack exchange,提问作者Chitransh Agarwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:14:54