工具类核心功能
// 示例:电商库存扣减场景
String lockKey = "stock_lock:" + productId;
if (RedisUtils.tryLock(lockKey, 1000, 30000)) {
try {
// 执行库存扣减逻辑
} finally {
RedisUtils.unlock(lockKey);
}
}
// 示例:接口限流(每秒10次)
long permits = RedisUtils.rateLimiter(
"api_limit:login",
RateType.OVERALL,
10, 1
);
if (permits == -1) throw new RuntimeException("请求过于频繁");
// 发布订单创建消息
RedisUtils.publish("order:created", orderDTO, msg -> {
log.info("消息已送达:{}", msg.getId());
});
// 订阅订单消息
RedisUtils.subscribe("order:created", OrderDTO.class, msg -> {
// 处理订单消息
});
快速接入指南
<dependency>
<groupId>org.redissongroupId>
<artifactId>redisson-spring-boot-starterartifactId>
<version>3.21.0version>
dependency>
spring:
redis:
host: 127.0.0.1
port: 6379
# 集群模式配置示例
# cluster:
# nodes: 192.168.0.1:7000,192.168.0.2:7001
⚠️ 关键注意事项 - 分布式锁必须成对使用
// 错误示例(缺少try-finally)
if (RedisUtils.tryLock(lockKey)) {
// 业务代码
RedisUtils.unlock(lockKey); // 可能无法执行
}
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.redisson.api.options.KeysScanOptions;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Redis 工具类
*
* @author Devil
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RedisUtils {
private static final RedissonClient CLIENT = SpringUtil.getBean(RedissonClient.class);
/* ---------------------- 分布式锁操作 ---------------------- */
/**
* 执行带锁的操作(自动释放)
*
* @param lockKey 锁名称
* @param waitTime 等待时间(秒)
* @param leaseTime 持有时间(秒)
* @param action 业务逻辑
*/
public static void executeWithLock(String lockKey, long waitTime, long leaseTime, Runnable action) {
RLock lock = getLock(lockKey);
try {
if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
action.run();
} else {
log.error("Redis Acquisition lock timeout, key: {}", lockKey);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("Redis Lock acquisition interrupt, key: {}", lockKey, e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
/**
* 快速执行带锁操作(默认等待3秒,自动续期)
*
* @param lockKey 锁名称
* @param action 业务逻辑
*/
public static void executeWithLock(String lockKey, Runnable action) {
executeWithLock(lockKey, 3, -1, action);
}
/**
* 获取分布式锁对象
*
* @param lockKey 锁键名
* @return RLock 锁对象
*/
public static RLock getLock(String lockKey) {
return CLIENT.getLock(lockKey);
}
/**
* 尝试获取锁(立即返回结果)
*
* @param lockKey 锁键名
* @return 是否获取成功
*/
public static boolean tryLock(String lockKey) {
RLock lock = getLock(lockKey);
try {
return lock.tryLock();
} catch (Exception e) {
log.error("Redis lock error, key: {}", lockKey, e);
return false;
}
}
/**
* 尝试获取锁(指定等待时间和持有时间)
*
* @param lockKey 锁键名
* @param waitTime 等待时间(毫秒)
* @param leaseTime 持有时间(毫秒)
* @return 是否获取成功
*/
public static boolean tryLock(String lockKey, long waitTime, long leaseTime) {
RLock lock = getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("Redis lock interrupted, key: {}", lockKey, e);
return false;
} catch (Exception e) {
log.error("Redis lock error, key: {}", lockKey, e);
return false;
}
}
/**
* 释放分布式锁
*
* @param lockKey 锁键名
*/
public static void unlock(String lockKey) {
RLock lock = getLock(lockKey);
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
try {
lock.unlock();
} catch (IllegalMonitorStateException e) {
log.error("Redis unlock error: lock not held by current thread, key: {}", lockKey);
}
}
}
/**
* 强制释放分布式锁(慎用)
*
* @param lockKey 锁键名
*/
public static void forceUnlock(String lockKey) {
RLock lock = getLock(lockKey);
if (lock.isLocked()) {
lock.forceUnlock();
}
}
/**
* 检查锁是否被任意线程持有
*
* @param lockKey 锁键名
* @return 是否被锁定
*/
public static boolean isLocked(String lockKey) {
return getLock(lockKey).isLocked();
}
/* ---------------------- 限流操作 ---------------------- */
/**
* 限流操作
*
* @param key 限流键名
* @param rateType 限流类型
* @param rate 速率(单位时间内允许的请求数)
* @param rateInterval 速率间隔(秒)
* @return 剩余许可数(-1 表示限流)
*/
public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
return rateLimiter(key, rateType, rate, rateInterval, 0);
}
/**
* 带超时时间的限流操作
*
* @param key 限流键名
* @param rateType 限流类型
* @param rate 速率
* @param rateInterval 速率间隔(秒)
* @param timeout 超时时间(秒)
* @return 剩余许可数(-1 表示限流)
*/
public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval, int timeout) {
validateKey(key);
RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
try {
rateLimiter.trySetRate(rateType, rate, Duration.ofSeconds(rateInterval), Duration.ofSeconds(timeout));
if (rateLimiter.tryAcquire()) {
return rateLimiter.availablePermits();
}
} catch (Exception e) {
log.error("Redis rate limiter error, key: {}", key, e);
}
return -1L;
}
/* ---------------------- 发布订阅 ---------------------- */
/**
* 发布消息到指定频道(带回调)
*/
public static <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
validateKey(channelKey);
try {
RTopic topic = CLIENT.getTopic(channelKey);
long receivers = topic.publish(msg);
log.debug("Message published to {} channels, key: {}", receivers, channelKey);
consumer.accept(msg);
} catch (Exception e) {
log.error("Redis publish error, key: {}", channelKey, e);
}
}
/**
* 发布消息到指定频道
*/
public static <T> void publish(String channelKey, T msg) {
publish(channelKey, msg, t -> {
});
}
/**
* 订阅指定频道的消息
*/
public static <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
validateKey(channelKey);
RTopic topic = CLIENT.getTopic(channelKey);
topic.addListener(clazz, (channel, msg) -> {
log.debug("Message received from channel: {}", channel);
consumer.accept(msg);
});
}
/* ---------------------- 键值操作 ---------------------- */
/**
* 缓存基本对象(永久有效)
*/
public static <T> void setCacheObject(String key, T value) {
setCacheObject(key, value, false, null);
}
/**
* 缓存基本对象(可保留TTL)
*/
public static <T> void setCacheObject(String key, T value, boolean keepTTL) {
setCacheObject(key, value, keepTTL, null);
}
/**
* 缓存基本对象(指定有效期)
*/
public static <T> void setCacheObject(String key, T value, Duration duration) {
setCacheObject(key, value, false, duration);
}
private static <T> void setCacheObject(String key, T value, boolean keepTTL, Duration duration) {
validateKeyValue(key, value);
RBucket<T> bucket = CLIENT.getBucket(key);
try {
if (keepTTL) {
bucket.setAndKeepTTL(value);
} else if (duration != null) {
bucket.set(value, duration);
} else {
bucket.set(value);
}
} catch (Exception e) {
log.error("Redis set cache error, key: {}", key, e);
}
}
/**
* 安全获取缓存对象
*/
public static <T> T getCacheObject(String key) {
validateKey(key);
try {
RBucket<T> bucket = CLIENT.getBucket(key);
return bucket.get();
} catch (Exception e) {
log.error("Redis get cache error, key: {}", key, e);
return null;
}
}
/**
* 设置有效时间
*/
public static boolean expire(String key, Duration duration) {
validateKey(key);
RBucket<Object> rBucket = CLIENT.getBucket(key);
try {
return rBucket.expire(duration);
} catch (Exception e) {
log.error("Redis expire error, key: {}", key, e);
return false;
}
}
/**
* 删除单个对象
*/
public static boolean deleteObject(String key) {
validateKey(key);
try {
return CLIENT.getBucket(key).delete();
} catch (Exception e) {
log.error("Redis delete error, key: {}", key, e);
return false;
}
}
/**
* 批量删除键
*/
public static long deleteKeys(String... keys) {
if (keys == null || keys.length == 0) return 0;
try {
return CLIENT.getKeys().delete(keys);
} catch (Exception e) {
log.error("Redis delete keys error", e);
return 0;
}
}
/**
* 检查缓存对象是否存在
*/
public static boolean isExistsObject(String key) {
validateKey(key);
try {
return CLIENT.getBucket(key).isExists();
} catch (Exception e) {
log.error("Redis exists check error, key: {}", key, e);
return false;
}
}
/* ---------------------- 列表操作 ---------------------- */
/**
* 缓存List数据
*/
public static <T> boolean setCacheList(String key, List<T> dataList) {
validateKeyValue(key, dataList);
RList<T> rList = CLIENT.getList(key);
try {
return rList.addAll(dataList);
} catch (Exception e) {
log.error("Redis set list error, key: {}", key, e);
return false;
}
}
/**
* 获取缓存列表
*/
public static <T> List<T> getCacheList(String key) {
validateKey(key);
RList<T> rList = CLIENT.getList(key);
try {
return rList.readAll();
} catch (Exception e) {
log.error("Redis get list error, key: {}", key, e);
return null;
}
}
/* ---------------------- 集合操作 ---------------------- */
/**
* 缓存Set数据
*/
public static <T> boolean setCacheSet(String key, Set<T> dataSet) {
validateKeyValue(key, dataSet);
RSet<T> rSet = CLIENT.getSet(key);
try {
return rSet.addAll(dataSet);
} catch (Exception e) {
log.error("Redis set error, key: {}", key, e);
return false;
}
}
/**
* 获取缓存集合
*/
public static <T> Set<T> getCacheSet(String key) {
validateKey(key);
RSet<T> rSet = CLIENT.getSet(key);
try {
return rSet.readAll();
} catch (Exception e) {
log.error("Redis get set error, key: {}", key, e);
return null;
}
}
/* ---------------------- 哈希操作 ---------------------- */
/**
* 缓存Map数据
*/
public static <T> void setCacheMap(String key, Map<String, T> dataMap) {
validateKeyValue(key, dataMap);
RMap<String, T> rMap = CLIENT.getMap(key);
try {
rMap.putAll(dataMap);
} catch (Exception e) {
log.error("Redis set map error, key: {}", key, e);
}
}
/**
* 获取缓存Map
*/
public static <T> Map<String, T> getCacheMap(String key) {
validateKey(key);
RMap<String, T> rMap = CLIENT.getMap(key);
try {
return rMap.getAll(rMap.keySet());
} catch (Exception e) {
log.error("Redis get map error, key: {}", key, e);
return null;
}
}
/* ---------------------- 原子操作 ---------------------- */
/**
* 设置原子值
*/
public static void setAtomicValue(String key, long value) {
validateKey(key);
RAtomicLong atomic = CLIENT.getAtomicLong(key);
try {
atomic.set(value);
} catch (Exception e) {
log.error("Redis set atomic error, key: {}", key, e);
}
}
/**
* 递增原子值
*/
public static long incrAtomicValue(String key) {
validateKey(key);
RAtomicLong atomic = CLIENT.getAtomicLong(key);
try {
return atomic.incrementAndGet();
} catch (Exception e) {
log.error("Redis incr atomic error, key: {}", key, e);
return -1;
}
}
/**
* 递减原子值
*/
public static long decrementAndGet(String key) {
validateKey(key);
RAtomicLong atomic = CLIENT.getAtomicLong(key);
try {
return atomic.decrementAndGet();
} catch (Exception e) {
log.error("Redis decr atomic error, key: {}", key, e);
return -1;
}
}
/* ---------------------- 工具方法 ---------------------- */
private static void validateKey(String key) {
if (StrUtil.isBlank(key)) {
throw new IllegalArgumentException("Redis key cannot be blank");
}
}
private static <T> void validateKeyValue(String key, T value) {
validateKey(key);
if (value == null) {
throw new IllegalArgumentException("Redis value cannot be null");
}
}
/**
* 事务执行模板
*/
public static void executeInTransaction(Consumer<RBatch> action) {
RBatch batch = CLIENT.createBatch(BatchOptions.defaults().executionMode(BatchOptions.ExecutionMode.IN_MEMORY_ATOMIC));
try {
action.accept(batch);
batch.execute();
} catch (Exception e) {
log.error("Redis transaction error", e);
batch.discard();
}
}
/**
* 扫描键集合
*/
public static Collection<String> keys(KeysScanOptions keysScanOptions) {
try {
Stream<String> keysStream = CLIENT.getKeys().getKeysStream(keysScanOptions);
return keysStream.collect(Collectors.toList());
} catch (Exception e) {
log.error("Redis keys scan error", e);
return null;
}
}
/**
* 获取Redisson客户端实例
*/
public static RedissonClient getClient() {
return CLIENT;
}
}