package edu.travel.cache.config; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeUnit; @Component public class RedisLock { // 锁键的前缀,可根据业务自定义 private static final String LOCK_PREFIX = "lock:"; private final StringRedisTemplate redisTemplate; public RedisLock(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } /** * 获取分布式锁(使用SETNX和过期时间,保证原子性) * * @param lockKey 锁的键 * @param expire 锁的过期时间(秒) * @return 锁的唯一标识(用于释放锁) */ public String acquireLock(String lockKey, long expire) { String lockValue = UUID.randomUUID().toString(); String key = LOCK_PREFIX + lockKey; // 使用SET命令:SET key value NX EX expire Boolean success = redisTemplate.opsForValue() .setIfAbsent(key, lockValue, expire, TimeUnit.SECONDS); return Boolean.TRUE.equals(success) ? lockValue : null; } /** * 释放分布式锁(使用Lua脚本保证原子性) * * @param lockKey 锁的键 * @param lockValue 锁的唯一标识 * @return 是否释放成功 */ public boolean releaseLock(String lockKey, String lockValue) { if (lockValue == null) return false; String key = LOCK_PREFIX + lockKey; String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + "return redis.call('del', KEYS[1]) " + "else return 0 end"; RedisScript redisScript = new DefaultRedisScript<>(script, Long.class); Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), lockValue); return result != null && result == 1; } }