SpringVortexNotes

分布式锁工厂替换 Redisson 直连

zjc 于 2026-08-24 发布

代码环境

商品购买最初直接注入 RedissonClient,能跑通,但业务代码被迫知道锁的获取、中断、续期、解锁异常等细节。这次提交把这些细节下沉到公共模板:

public interface DistributedLockTemplate {
    <T> T execute(String lockKey, Duration waitTime, Supplier<T> action);

    <T> T execute(String lockKey, Duration waitTime,
                  String timeoutMessage, Supplier<T> action);
}

https://github.com/springvortex/spring-cloud-alibaba/blob/release/v1.0.0/service-common/src/main/java/com/zjc/common/lock/DistributedLockTemplate.java

业务侧变成:

distributedLockFactory.getTemplate().execute(
        PURCHASE_LOCK_KEY_PREFIX + goodsId,
        LOCK_WAIT,
        "当前购买人数过多,请稍后再试",
        () -> purchaseInLock(goodsId, request));

https://github.com/springvortex/spring-cloud-alibaba/blob/release/v1.0.0/service-provider/src/main/java/com/zjc/provider/service/impl/GoodsPurchaseServiceImpl.java

默认实现由配置选择:

zjc:
  distributed-lock:
    provider: redis
    mysql:
      table-name: t_distributed_lock
      lease-time: 30s
      retry-interval: 100ms

https://github.com/springvortex/spring-cloud-alibaba/blob/release/v1.0.0/service-provider/src/main/resources/config/application-lock.yaml

当前支持三种 Provider:

Provider 状态 说明
redis 可用 Redisson 可重入锁,不传租期时由看门狗续期
mysql 可用 租约表、唯一键、行事务、重入计数和后台续期
zookeeper 占位 显式抛出未实现,保留后续接入 Curator 的位置

MySQL 实现使用 lock_key 唯一键和 SELECT ... FOR UPDATE 完成抢锁,每个线程有独立 owner,支持重入计数;持有期间按租期的三分之一续期,进程崩溃后等待租约到期释放。表名通过白名单正则校验后才拼接 SQL,避免配置注入。

公共模块中的 Redisson、JDBC 和事务依赖都是 optional。自动配置根据已有 Bean 装配可用实现:有 RedissonClient 就提供 Redis 模板,有 JdbcTemplate 和事务管理器才提供 MySQL 模板。不需要锁或没有对应基础设施的服务,不会被强制引入依赖。

这个抽象的边界也清楚:它解决“用统一方式拿锁和释放锁”,不把业务事务包进锁模板。商品购买仍在回调里使用 TransactionTemplate,数据库条件更新依旧是最后兜底。

经验总结

当锁的语义开始包含等待、超时、中断和释放异常时,业务代码不应该直接面对具体客户端 API。统一模板保留业务语义,把存储差异和释放细节留在基础设施层。

评论

评论由 GitHub Discussions 承载,需要 GitHub 账号登录。