一、分布式锁核心设计原则实现分布式锁需满足以下核心要求缺一不可互斥性同一时间只能有一个客户端持有锁非阻塞获取锁失败时直接返回不阻塞超时释放防止客户端持有锁后宕机导致锁永久无法释放原子性加锁、解锁操作必须是原子的避免并发下出现锁异常可重入可选同一客户端持有锁后可重复获取锁。二、技术选型与依赖准备1. 核心依赖Maven!-- SpringBoot Redis 整合依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency!-- 连接池提升Redis性能 --dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId/dependency!-- JSON序列化可选用于存储复杂值 --dependencygroupIdcom.alibaba/groupIdartifactIdfastjson2/artifactIdversion2.0.41/version/dependency2. Redis 配置application.ymlspring:redis:host:127.0.0.1port:6379password:# 无密码则留空database:0lettuce:pool:max-active:8# 最大连接数max-idle:8# 最大空闲连接min-idle:0# 最小空闲连接max-wait:-1ms# 连接等待时间三、核心实现Redis 分布式锁工具类基于 Redis 的SET NX EX命令实现原子加锁结合 Lua 脚本实现原子解锁避免“误删锁”问题完整工具类如下importorg.springframework.data.redis.core.RedisCallback;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.core.script.DefaultRedisScript;importorg.springframework.stereotype.Component;importjavax.annotation.Resource;importjava.util.Collections;importjava.util.UUID;importjava.util.concurrent.TimeUnit;/** * Redis 分布式锁工具类可重入、原子操作、超时释放 */ComponentpublicclassRedisDistributedLock{ResourceprivateRedisTemplateString,StringredisTemplate;// 锁前缀避免key冲突privatestaticfinalStringLOCK_PREFIXdistributed:lock:;// 线程本地存储存储当前线程持有的锁标识用于可重入privatestaticfinalThreadLocalStringLOCK_IDENTIFIERnewThreadLocal();/** * 获取分布式锁 * param lockKey 锁标识如order:1001 * param expireTime 锁过期时间毫秒 * return 是否获取成功 */publicbooleanlock(StringlockKey,longexpireTime){StringrealKeyLOCK_PREFIXlockKey;StringidentifierLOCK_IDENTIFIER.get();// 可重入逻辑当前线程已持有锁直接返回成功if(identifier!nullredisTemplate.hasKey(realKey)identifier.equals(redisTemplate.opsForValue().get(realKey))){returntrue;}// 生成唯一标识避免误删其他线程的锁identifierUUID.randomUUID().toString();// SET NX EX 命令原子性加锁不存在则设置同时设置过期时间BooleansuccessredisTemplate.opsForValue().setIfAbsent(realKey,identifier,expireTime,TimeUnit.MILLISECONDS);if(Boolean.TRUE.equals(success)){LOCK_IDENTIFIER.set(identifier);returntrue;}returnfalse;}/** * 释放分布式锁Lua脚本保证原子性 * param lockKey 锁标识 * return 是否释放成功 */publicbooleanunlock(StringlockKey){StringrealKeyLOCK_PREFIXlockKey;StringidentifierLOCK_IDENTIFIER.get();// 未持有锁直接返回if(identifiernull){returnfalse;}// Lua脚本判断标识是否匹配匹配则删除原子操作StringluaScript if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end ;DefaultRedisScriptLongredisScriptnewDefaultRedisScript();redisScript.setScriptText(luaScript);redisScript.setResultType(Long.class);// 执行脚本LongresultredisTemplate.execute(redisScript,Collections.singletonList(realKey),identifier);// 释放成功清除线程本地标识if(result!nullresult0){LOCK_IDENTIFIER.remove();returntrue;}returnfalse;}}四、使用示例业务场景以“订单创建”为例演示分布式锁的使用避免同一订单被重复创建importorg.springframework.stereotype.Service;importjavax.annotation.Resource;ServicepublicclassOrderService{ResourceprivateRedisDistributedLockredisDistributedLock;/** * 创建订单加分布式锁防重复 * param orderId 订单ID * return 创建结果 */publicStringcreateOrder(StringorderId){// 1. 定义锁标识和过期时间5秒避免死锁StringlockKeyorder:orderId;longexpireTime5000;// 2. 获取锁if(!redisDistributedLock.lock(lockKey,expireTime)){return操作太频繁请稍后再试;}try{// 3. 核心业务逻辑模拟订单创建System.out.println(开始创建订单orderId);// 业务处理...return订单创建成功orderId;}finally{// 4. 释放锁必须在finally中执行避免异常导致锁无法释放redisDistributedLock.unlock(lockKey);}}}五、关键避坑点避免硬编码过期时间根据业务耗时合理设置过短可能导致业务未完成锁已释放过长可能导致锁占用时间久锁标识必须唯一使用UUID生成避免同一锁被不同线程释放解锁必须在finally中无论业务是否抛出异常都要释放锁可重入设计通过ThreadLocal存储当前线程的锁标识支持同一线程多次获取锁。总结SpringBoot整合Redis实现分布式锁的核心是SET NX EX原子加锁 Lua脚本原子解锁解决互斥性和原子性问题工具类需实现可重入、超时释放、防误删核心特性适配生产环境使用时需注意锁过期时间设置、解锁操作的原子性以及finally中释放锁的规范。