Redis工具类
依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>代码:
java
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Redis 工具类
*
* <p>覆盖 String / Hash / List / Set / ZSet 五种数据结构的常用操作,
* 提供丰富重载,并通过 Jackson ObjectMapper 对值进行自动类型转换。</p>
*
* <h3>类型转换说明</h3>
* <pre>
* // 存入 POJO
* redisUtil.set("user:1", user);
*
* // 按原类型取出
* User user = redisUtil.get("user:1", User.class);
*
* // 取出泛型复杂类型(如 List<User>)
* List<User> list = redisUtil.get("users", new TypeReference<List<User>>() {});
* </pre>
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/** Spring Boot 自动配置的 Jackson ObjectMapper,用于 POJO 类型转换 */
@Autowired
private ObjectMapper objectMapper;
// ================================================================
// 内部工具:类型转换
// ================================================================
/**
* 将 Redis 返回的原始值转换为目标类型(支持 POJO、Map 等)。
* 当 RedisTemplate 使用 Jackson 序列化时,返回值可能已是 LinkedHashMap,
* objectMapper.convertValue 会将其正确地转换为目标 POJO。
*/
@SuppressWarnings("unchecked")
private <T> T convert(Object raw, Class<T> clazz) {
if (raw == null) return null;
if (clazz.isInstance(raw)) return clazz.cast(raw);
return objectMapper.convertValue(raw, clazz);
}
/** 转换为泛型复杂类型,例如 {@code new TypeReference<List<User>>() {}} */
private <T> T convert(Object raw, TypeReference<T> typeRef) {
if (raw == null) return null;
return objectMapper.convertValue(raw, typeRef);
}
// ================================================================
// Key 相关操作
// ================================================================
/**
* 设置 key 过期时间(秒)
*
* @return true 设置成功;false 失败
*/
public boolean expire(String key, long seconds) {
return expire(key, seconds, TimeUnit.SECONDS);
}
/**
* 设置 key 过期时间(指定单位)
*
* @return true 设置成功;false 失败
*/
public boolean expire(String key, long time, TimeUnit timeUnit) {
try {
if (time > 0) {
return Boolean.TRUE.equals(redisTemplate.expire(key, time, timeUnit));
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 获取 key 的剩余过期时间(秒)
*
* @return 剩余秒数;-1 表示永久;-2 表示 key 不存在
*/
public long getExpire(String key) {
return getExpire(key, TimeUnit.SECONDS);
}
/**
* 获取 key 的剩余过期时间(指定单位)
*
* @return 剩余时间;-1 表示永久;-2 表示 key 不存在
*/
public long getExpire(String key, TimeUnit timeUnit) {
Long ttl = redisTemplate.getExpire(key, timeUnit);
return ttl == null ? -2L : ttl;
}
/**
* 移除 key 的过期时间,使其永久存在(PERSIST)
*
* @return true 成功;false key 不存在或已永久
*/
public boolean persist(String key) {
return Boolean.TRUE.equals(redisTemplate.persist(key));
}
/**
* 判断 key 是否存在
*/
public boolean hasKey(String key) {
try {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 获取 key 存储的数据类型(string / hash / list / set / zset / none)
*/
public String type(String key) {
DataType dataType = redisTemplate.type(key);
return dataType == null ? "none" : dataType.code();
}
/**
* 删除单个 key
*
* @return true 删除成功
*/
public boolean del(String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
/**
* 批量删除 key(varargs)
*
* @return 实际删除数量
*/
public long del(String... keys) {
if (keys == null || keys.length == 0) return 0L;
@SuppressWarnings("unchecked")
Collection<String> keyList = (Collection<String>) CollectionUtils.arrayToList(keys);
Long count = redisTemplate.delete(keyList);
return count == null ? 0L : count;
}
/**
* 批量删除 key(Collection)
*
* @return 实际删除数量
*/
public long del(Collection<String> keys) {
if (CollectionUtils.isEmpty(keys)) return 0L;
Long count = redisTemplate.delete(keys);
return count == null ? 0L : count;
}
/**
* 模糊匹配获取所有符合条件的 key(KEYS pattern)
*
* <p><strong>警告:</strong>生产环境数据量大时请使用 {@link #scan} 代替。</p>
*/
public Set<String> keys(String pattern) {
return redisTemplate.keys(pattern);
}
/**
* 使用 SCAN 游标安全地遍历匹配 key(推荐替代 keys)
*
* @param pattern 匹配模式,例如 {@code "user:*"}
* @param count 每次扫描的建议数量(仅提示 Redis,实际数量不保证)
*/
public List<String> scan(String pattern, long count) {
List<String> result = new ArrayList<>();
try (Cursor<String> cursor = redisTemplate.scan(
ScanOptions.scanOptions().match(pattern).count(count).build())) {
while (cursor.hasNext()) {
result.add(cursor.next());
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 重命名 key
*/
public boolean rename(String oldKey, String newKey) {
try {
redisTemplate.rename(oldKey, newKey);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 仅当 newKey 不存在时重命名(RENAMENX)
*
* @return true 重命名成功;false newKey 已存在
*/
public boolean renameIfAbsent(String oldKey, String newKey) {
return Boolean.TRUE.equals(redisTemplate.renameIfAbsent(oldKey, newKey));
}
// ================================================================
// String 操作
// ================================================================
/**
* 获取值(原始 Object)
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 获取值并自动转换为目标类型
*
* <pre>User user = redisUtil.get("user:1", User.class);</pre>
*/
public <T> T get(String key, Class<T> clazz) {
return convert(get(key), clazz);
}
/**
* 获取值并转换为泛型复杂类型
*
* <pre>List<User> users = redisUtil.get("users", new TypeReference<List<User>>() {});</pre>
*/
public <T> T get(String key, TypeReference<T> typeRef) {
return convert(get(key), typeRef);
}
/** 获取字符串值 */
public String getString(String key) {
Object val = get(key);
return val == null ? null : val.toString();
}
/** 获取 Integer 值 */
public Integer getInteger(String key) {
return get(key, Integer.class);
}
/** 获取 Long 值(兼容存入时为 Integer 的情况) */
public Long getLong(String key) {
Object val = get(key);
if (val == null) return null;
if (val instanceof Long) return (Long) val;
if (val instanceof Number) return ((Number) val).longValue();
return Long.parseLong(val.toString());
}
/** 获取 Double 值 */
public Double getDouble(String key) {
Object val = get(key);
if (val == null) return null;
if (val instanceof Double) return (Double) val;
if (val instanceof Number) return ((Number) val).doubleValue();
return Double.parseDouble(val.toString());
}
/**
* 批量获取(MGET),返回顺序与 keys 一致,缺失项为 null
*/
public List<Object> mGet(Collection<String> keys) {
return redisTemplate.opsForValue().multiGet(keys);
}
/**
* 批量获取并将每个值转换为指定类型
*/
public <T> List<T> mGet(Collection<String> keys, Class<T> clazz) {
List<Object> raw = mGet(keys);
if (raw == null) return Collections.emptyList();
List<T> result = new ArrayList<>(raw.size());
raw.forEach(obj -> result.add(convert(obj, clazz)));
return result;
}
/**
* 设置值(永久)
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 设置值(秒级过期)
*/
public boolean set(String key, Object value, long seconds) {
return set(key, value, seconds, TimeUnit.SECONDS);
}
/**
* 设置值(指定单位过期)
*/
public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, timeUnit);
} else {
redisTemplate.opsForValue().set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 仅当 key 不存在时设置,永久(SET NX)
*
* @return true 设置成功;false key 已存在
*/
public boolean setIfAbsent(String key, Object value) {
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value));
}
/**
* 仅当 key 不存在时设置,秒级过期(SET NX EX)
*
* @return true 设置成功;false key 已存在
*/
public boolean setIfAbsent(String key, Object value, long seconds) {
return setIfAbsent(key, value, seconds, TimeUnit.SECONDS);
}
/**
* 仅当 key 不存在时设置,指定单位过期
*
* @return true 设置成功;false key 已存在
*/
public boolean setIfAbsent(String key, Object value, long time, TimeUnit timeUnit) {
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit));
}
/**
* 仅当 key 存在时更新值(SET XX),永久
*
* @return true 更新成功;false key 不存在
*/
public boolean setIfPresent(String key, Object value) {
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfPresent(key, value));
}
/**
* 仅当 key 存在时更新值,秒级过期
*/
public boolean setIfPresent(String key, Object value, long seconds) {
return setIfPresent(key, value, seconds, TimeUnit.SECONDS);
}
/**
* 仅当 key 存在时更新值,指定单位过期
*/
public boolean setIfPresent(String key, Object value, long time, TimeUnit timeUnit) {
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfPresent(key, value, time, timeUnit));
}
/**
* 设置值并返回旧值(GETSET)
*/
public Object getAndSet(String key, Object value) {
return redisTemplate.opsForValue().getAndSet(key, value);
}
/**
* 设置值并返回旧值,转换为指定类型
*/
public <T> T getAndSet(String key, Object value, Class<T> clazz) {
return convert(getAndSet(key, value), clazz);
}
/**
* 批量设置(MSET),永久
*/
public boolean mSet(Map<String, Object> map) {
try {
redisTemplate.opsForValue().multiSet(map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 批量设置,仅当所有 key 都不存在时生效(MSETNX)
*
* @return true 全部设置成功;false 至少有一个 key 已存在
*/
public boolean mSetIfAbsent(Map<String, Object> map) {
return Boolean.TRUE.equals(redisTemplate.opsForValue().multiSetIfAbsent(map));
}
/**
* 追加字符串到已有值末尾(APPEND)
*
* @return 追加后字符串的字节长度
*/
public int append(String key, String value) {
Integer len = redisTemplate.opsForValue().append(key, value);
return len == null ? 0 : len;
}
/**
* 获取字符串字节长度(STRLEN)
*/
public long strlen(String key) {
Long len = redisTemplate.opsForValue().size(key);
return len == null ? 0L : len;
}
/**
* 自增 1(INCR)
*
* @return 自增后的值
*/
public long incr(String key) {
return incr(key, 1L);
}
/**
* 自增指定步长(INCRBY),delta 必须 > 0
*
* @return 自增后的值
*/
public long incr(String key, long delta) {
if (delta <= 0) throw new IllegalArgumentException("递增因子必须大于 0");
Long val = redisTemplate.opsForValue().increment(key, delta);
return val == null ? 0L : val;
}
/**
* 自减 1(DECR)
*
* @return 自减后的值
*/
public long decr(String key) {
return decr(key, 1L);
}
/**
* 自减指定步长,delta 必须 > 0
*
* @return 自减后的值
*/
public long decr(String key, long delta) {
if (delta <= 0) throw new IllegalArgumentException("递减因子必须大于 0");
Long val = redisTemplate.opsForValue().increment(key, -delta);
return val == null ? 0L : val;
}
// ================================================================
// Hash 操作(对应 Java Map)
// ================================================================
/**
* 获取 Hash 中指定字段的值(原始 Object)
*/
public Object hGet(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}
/**
* 获取 Hash 中指定字段的值并自动转换类型
*
* <pre>User user = redisUtil.hGet("users", "user001", User.class);</pre>
*/
public <T> T hGet(String key, String field, Class<T> clazz) {
return convert(hGet(key, field), clazz);
}
/**
* 获取 Hash 中指定字段的值并转换为泛型复杂类型
*/
public <T> T hGet(String key, String field, TypeReference<T> typeRef) {
return convert(hGet(key, field), typeRef);
}
/**
* 获取 Hash 所有字段及值(HGETALL)
*/
public Map<Object, Object> hGetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 获取 Hash 所有字段及值,将 value 转换为指定类型(Map<String, T>)
*
* <pre>Map<String, User> map = redisUtil.hGetAll("users", User.class);</pre>
*/
public <T> Map<String, T> hGetAll(String key, Class<T> clazz) {
Map<Object, Object> raw = hGetAll(key);
if (raw == null || raw.isEmpty()) return Collections.emptyMap();
Map<String, T> result = new LinkedHashMap<>(raw.size());
raw.forEach((k, v) -> result.put(k.toString(), convert(v, clazz)));
return result;
}
/**
* 批量获取 Hash 中指定字段的值(HMGET)
*/
public List<Object> hMultiGet(String key, Collection<String> fields) {
return redisTemplate.opsForHash().multiGet(key, new ArrayList<>(fields));
}
/**
* 批量获取 Hash 中指定字段的值并转换类型
*/
public <T> List<T> hMultiGet(String key, Collection<String> fields, Class<T> clazz) {
List<Object> raw = hMultiGet(key, fields);
if (raw == null) return Collections.emptyList();
List<T> result = new ArrayList<>(raw.size());
raw.forEach(obj -> result.add(convert(obj, clazz)));
return result;
}
/**
* 设置 Hash 中单个字段(HSET)
*/
public boolean hSet(String key, String field, Object value) {
try {
redisTemplate.opsForHash().put(key, field, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 设置 Hash 中单个字段,并刷新 key 的过期时间(秒)
*/
public boolean hSet(String key, String field, Object value, long seconds) {
return hSet(key, field, value, seconds, TimeUnit.SECONDS);
}
/**
* 设置 Hash 中单个字段,并刷新 key 的过期时间(指定单位)
*/
public boolean hSet(String key, String field, Object value, long time, TimeUnit timeUnit) {
try {
redisTemplate.opsForHash().put(key, field, value);
if (time > 0) expire(key, time, timeUnit);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 仅当字段不存在时设置(HSETNX)
*
* @return true 设置成功;false 字段已存在
*/
public boolean hSetIfAbsent(String key, String field, Object value) {
return Boolean.TRUE.equals(redisTemplate.opsForHash().putIfAbsent(key, field, value));
}
/**
* 批量设置 Hash 字段(HMSET)
*/
public boolean hSetAll(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 批量设置 Hash 字段,并设置过期时间(秒)
*/
public boolean hSetAll(String key, Map<String, Object> map, long seconds) {
return hSetAll(key, map, seconds, TimeUnit.SECONDS);
}
/**
* 批量设置 Hash 字段,并设置过期时间(指定单位)
*/
public boolean hSetAll(String key, Map<String, Object> map, long time, TimeUnit timeUnit) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) expire(key, time, timeUnit);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除 Hash 中的字段(HDEL),支持多个
*
* @return 实际删除数量
*/
public long hDel(String key, String... fields) {
return redisTemplate.opsForHash().delete(key, (Object[]) fields);
}
/**
* 判断 Hash 中字段是否存在(HEXISTS)
*/
public boolean hHasKey(String key, String field) {
return redisTemplate.opsForHash().hasKey(key, field);
}
/**
* 获取 Hash 所有字段名(HKEYS)
*/
public Set<Object> hKeys(String key) {
return redisTemplate.opsForHash().keys(key);
}
/**
* 获取 Hash 所有字段值列表(HVALS)
*/
public List<Object> hValues(String key) {
return redisTemplate.opsForHash().values(key);
}
/**
* 获取 Hash 所有字段值列表并转换类型
*/
public <T> List<T> hValues(String key, Class<T> clazz) {
List<Object> raw = hValues(key);
if (raw == null) return Collections.emptyList();
List<T> result = new ArrayList<>(raw.size());
raw.forEach(obj -> result.add(convert(obj, clazz)));
return result;
}
/**
* 获取 Hash 字段数量(HLEN)
*/
public long hSize(String key) {
return redisTemplate.opsForHash().size(key);
}
/**
* Hash 字段数值自增 1(long)
*/
public long hIncr(String key, String field) {
return hIncr(key, field, 1L);
}
/**
* Hash 字段数值自增(long)
*/
public long hIncr(String key, String field, long delta) {
return redisTemplate.opsForHash().increment(key, field, delta);
}
/**
* Hash 字段数值自增(double,支持浮点步长)
*/
public double hIncr(String key, String field, double delta) {
return redisTemplate.opsForHash().increment(key, field, delta);
}
/**
* Hash 字段数值自减 1(long)
*/
public long hDecr(String key, String field) {
return hDecr(key, field, 1L);
}
/**
* Hash 字段数值自减(long)
*/
public long hDecr(String key, String field, long delta) {
return redisTemplate.opsForHash().increment(key, field, -delta);
}
/**
* Hash 字段数值自减(double)
*/
public double hDecr(String key, String field, double delta) {
return redisTemplate.opsForHash().increment(key, field, -delta);
}
// ================================================================
// List 操作
// ================================================================
/**
* 获取 List 全部元素
*/
public List<Object> lRange(String key) {
return lRange(key, 0, -1);
}
/**
* 获取 List 全部元素并转换类型
*
* <pre>List<User> users = redisUtil.lRange("users", User.class);</pre>
*/
public <T> List<T> lRange(String key, Class<T> clazz) {
return lRange(key, 0, -1, clazz);
}
/**
* 获取 List 指定范围元素(LRANGE),0 到 -1 表示全部
*/
public List<Object> lRange(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
}
}
/**
* 获取 List 指定范围元素并转换类型
*/
public <T> List<T> lRange(String key, long start, long end, Class<T> clazz) {
List<Object> raw = lRange(key, start, end);
if (raw == null) return Collections.emptyList();
List<T> result = new ArrayList<>(raw.size());
raw.forEach(obj -> result.add(convert(obj, clazz)));
return result;
}
/**
* 获取 List 长度(LLEN)
*/
public long lSize(String key) {
try {
Long size = redisTemplate.opsForList().size(key);
return size == null ? 0L : size;
} catch (Exception e) {
e.printStackTrace();
return 0L;
}
}
/**
* 按索引获取元素(LINDEX);index 为负数时从尾部计数(-1 为末尾)
*/
public Object lIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 按索引获取元素并转换类型
*/
public <T> T lIndex(String key, long index, Class<T> clazz) {
return convert(lIndex(key, index), clazz);
}
/**
* 右侧压入单个元素(RPUSH)
*/
public boolean rPush(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 右侧压入单个元素,并设置过期时间(秒)
*/
public boolean rPush(String key, Object value, long seconds) {
return rPush(key, value, seconds, TimeUnit.SECONDS);
}
/**
* 右侧压入单个元素,并设置过期时间(指定单位)
*/
public boolean rPush(String key, Object value, long time, TimeUnit timeUnit) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) expire(key, time, timeUnit);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 右侧批量压入(RPUSH 多个值)
*/
public boolean rPushAll(String key, List<Object> values) {
try {
redisTemplate.opsForList().rightPushAll(key, values);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 右侧批量压入,并设置过期时间(秒)
*/
public boolean rPushAll(String key, List<Object> values, long seconds) {
boolean ok = rPushAll(key, values);
if (ok && seconds > 0) expire(key, seconds);
return ok;
}
/**
* 左侧压入单个元素(LPUSH)
*/
public boolean lPush(String key, Object value) {
try {
redisTemplate.opsForList().leftPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 左侧批量压入(LPUSH 多个值)
*/
public boolean lPushAll(String key, List<Object> values) {
try {
redisTemplate.opsForList().leftPushAll(key, values);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 按索引更新 List 中指定位置的元素(LSET)
*/
public boolean lSet(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 左侧弹出一个元素(LPOP)
*/
public Object lPop(String key) {
return redisTemplate.opsForList().leftPop(key);
}
/**
* 左侧弹出一个元素并转换类型
*/
public <T> T lPop(String key, Class<T> clazz) {
return convert(lPop(key), clazz);
}
/**
* 右侧弹出一个元素(RPOP)
*/
public Object rPop(String key) {
return redisTemplate.opsForList().rightPop(key);
}
/**
* 右侧弹出一个元素并转换类型
*/
public <T> T rPop(String key, Class<T> clazz) {
return convert(rPop(key), clazz);
}
/**
* 阻塞式左侧弹出(BLPOP),超时后返回 null
*/
public Object blPop(String key, long timeout, TimeUnit timeUnit) {
return redisTemplate.opsForList().leftPop(key, timeout, timeUnit);
}
/**
* 阻塞式右侧弹出(BRPOP),超时后返回 null
*/
public Object brPop(String key, long timeout, TimeUnit timeUnit) {
return redisTemplate.opsForList().rightPop(key, timeout, timeUnit);
}
/**
* 移除 List 中值等于 value 的元素(LREM)
* <ul>
* <li>count > 0:从头向尾移除 count 个</li>
* <li>count < 0:从尾向头移除 |count| 个</li>
* <li>count = 0:移除全部匹配</li>
* </ul>
*
* @return 实际移除数量
*/
public long lRem(String key, long count, Object value) {
Long removed = redisTemplate.opsForList().remove(key, count, value);
return removed == null ? 0L : removed;
}
/**
* 裁剪 List,只保留 [start, end] 范围内的元素(LTRIM)
*/
public boolean lTrim(String key, long start, long end) {
try {
redisTemplate.opsForList().trim(key, start, end);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// ================================================================
// Set 操作(无序集合,元素唯一)
// ================================================================
/**
* 获取 Set 所有成员(SMEMBERS)
*/
public Set<Object> sMembers(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return Collections.emptySet();
}
}
/**
* 获取 Set 所有成员并转换类型
*
* <pre>Set<User> users = redisUtil.sMembers("onlineUsers", User.class);</pre>
*/
public <T> Set<T> sMembers(String key, Class<T> clazz) {
Set<Object> raw = sMembers(key);
if (raw == null) return Collections.emptySet();
Set<T> result = new LinkedHashSet<>(raw.size());
raw.forEach(obj -> result.add(convert(obj, clazz)));
return result;
}
/**
* 判断 value 是否是 Set 的成员(SISMEMBER)
*/
public boolean sIsMember(String key, Object value) {
return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, value));
}
/**
* 向 Set 添加元素(SADD),支持多个
*
* @return 成功添加的元素数量
*/
public long sAdd(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
return count == null ? 0L : count;
} catch (Exception e) {
e.printStackTrace();
return 0L;
}
}
/**
* 向 Set 添加元素,并设置过期时间(秒)
*
* @return 成功添加的元素数量
*/
public long sAdd(String key, long seconds, Object... values) {
long count = sAdd(key, values);
if (seconds > 0) expire(key, seconds);
return count;
}
/**
* 从 Set 中移除元素(SREM),支持多个
*
* @return 实际移除数量
*/
public long sRem(String key, Object... values) {
Long count = redisTemplate.opsForSet().remove(key, values);
return count == null ? 0L : count;
}
/**
* 随机弹出一个成员(SPOP,同时移除)
*/
public Object sPop(String key) {
return redisTemplate.opsForSet().pop(key);
}
/**
* 随机弹出一个成员并转换类型
*/
public <T> T sPop(String key, Class<T> clazz) {
return convert(sPop(key), clazz);
}
/**
* 随机弹出多个成员(SPOP count)
*/
public List<Object> sPop(String key, long count) {
return redisTemplate.opsForSet().pop(key, count);
}
/**
* 随机获取一个成员(不移除,SRANDMEMBER)
*/
public Object sRandMember(String key) {
return redisTemplate.opsForSet().randomMember(key);
}
/**
* 随机获取多个成员(不移除,可重复)
*/
public List<Object> sRandMembers(String key, long count) {
return redisTemplate.opsForSet().randomMembers(key, count);
}
/**
* 随机获取多个不重复成员(不移除)
*/
public Set<Object> sDistinctRandMembers(String key, long count) {
return redisTemplate.opsForSet().distinctRandomMembers(key, count);
}
/**
* 获取 Set 成员数量(SCARD)
*/
public long sSize(String key) {
Long size = redisTemplate.opsForSet().size(key);
return size == null ? 0L : size;
}
/**
* 获取两个 Set 的交集(SINTER)
*/
public Set<Object> sIntersect(String key, String otherKey) {
return redisTemplate.opsForSet().intersect(key, otherKey);
}
/**
* 获取多个 Set 的交集
*/
public Set<Object> sIntersect(String key, Collection<String> otherKeys) {
return redisTemplate.opsForSet().intersect(key, otherKeys);
}
/**
* 获取两个 Set 的并集(SUNION)
*/
public Set<Object> sUnion(String key, String otherKey) {
return redisTemplate.opsForSet().union(key, otherKey);
}
/**
* 获取多个 Set 的并集
*/
public Set<Object> sUnion(String key, Collection<String> otherKeys) {
return redisTemplate.opsForSet().union(key, otherKeys);
}
/**
* 获取两个 Set 的差集(SDIFF,key 有而 otherKey 无的元素)
*/
public Set<Object> sDiff(String key, String otherKey) {
return redisTemplate.opsForSet().difference(key, otherKey);
}
/**
* 获取多个 Set 的差集
*/
public Set<Object> sDiff(String key, Collection<String> otherKeys) {
return redisTemplate.opsForSet().difference(key, otherKeys);
}
// ================================================================
// ZSet 操作(有序集合,按 score 排序)
// ================================================================
/**
* 添加元素并指定 score(若已存在则更新 score)(ZADD)
*
* @return true 为新增;false 为更新
*/
public boolean zAdd(String key, Object value, double score) {
return Boolean.TRUE.equals(redisTemplate.opsForZSet().add(key, value, score));
}
/**
* 批量添加元素(ZADD 多个)
*
* @return 实际新增数量
*/
public long zAddAll(String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
Long count = redisTemplate.opsForZSet().add(key, tuples);
return count == null ? 0L : count;
}
/**
* 获取元素的 score(ZSCORE)
*/
public Double zScore(String key, Object value) {
return redisTemplate.opsForZSet().score(key, value);
}
/**
* 获取元素的正序排名(ZRANK,0 为最小 score)
*/
public Long zRank(String key, Object value) {
return redisTemplate.opsForZSet().rank(key, value);
}
/**
* 获取元素的逆序排名(ZREVRANK,0 为最大 score)
*/
public Long zReverseRank(String key, Object value) {
return redisTemplate.opsForZSet().reverseRank(key, value);
}
/**
* 按排名范围获取元素,正序(ZRANGE),0 到 -1 为全部
*/
public Set<Object> zRange(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
/**
* 获取全部元素,正序
*/
public Set<Object> zRange(String key) {
return zRange(key, 0, -1);
}
/**
* 按排名范围获取元素并转换类型,正序
*/
public <T> List<T> zRange(String key, long start, long end, Class<T> clazz) {
Set<Object> raw = zRange(key, start, end);
if (raw == null) return Collections.emptyList();
List<T> result = new ArrayList<>(raw.size());
raw.forEach(obj -> result.add(convert(obj, clazz)));
return result;
}
/**
* 按排名范围获取元素,逆序(ZREVRANGE)
*/
public Set<Object> zReverseRange(String key, long start, long end) {
return redisTemplate.opsForZSet().reverseRange(key, start, end);
}
/**
* 按排名范围获取带 score 的元素(ZRANGE WITHSCORES),正序
*/
public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start, long end) {
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
}
/**
* 按排名范围获取带 score 的元素,逆序
*/
public Set<ZSetOperations.TypedTuple<Object>> zReverseRangeWithScores(String key, long start, long end) {
return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
}
/**
* 按 score 范围获取元素(ZRANGEBYSCORE),正序
*/
public Set<Object> zRangeByScore(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
}
/**
* 按 score 范围获取元素(带分页偏移),正序
*/
public Set<Object> zRangeByScore(String key, double min, double max, long offset, long count) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max, offset, count);
}
/**
* 按 score 范围获取元素并转换类型,正序
*/
public <T> List<T> zRangeByScore(String key, double min, double max, Class<T> clazz) {
Set<Object> raw = zRangeByScore(key, min, max);
if (raw == null) return Collections.emptyList();
List<T> result = new ArrayList<>(raw.size());
raw.forEach(obj -> result.add(convert(obj, clazz)));
return result;
}
/**
* 按 score 范围获取元素(ZREVRANGEBYSCORE),逆序
*/
public Set<Object> zReverseRangeByScore(String key, double min, double max) {
return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
}
/**
* 按 score 范围获取带 score 的元素,正序
*/
public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
}
/**
* 元素 score 自增(ZINCRBY)
*
* @return 自增后的 score
*/
public double zIncr(String key, Object value, double delta) {
Double score = redisTemplate.opsForZSet().incrementScore(key, value, delta);
return score == null ? 0.0 : score;
}
/**
* 删除指定元素(ZREM),支持多个
*
* @return 实际删除数量
*/
public long zRem(String key, Object... values) {
Long count = redisTemplate.opsForZSet().remove(key, values);
return count == null ? 0L : count;
}
/**
* 按 score 范围删除元素(ZREMRANGEBYSCORE)
*
* @return 实际删除数量
*/
public long zRemByScore(String key, double min, double max) {
Long count = redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
return count == null ? 0L : count;
}
/**
* 按排名范围删除元素(ZREMRANGEBYRANK)
*
* @return 实际删除数量
*/
public long zRemByRank(String key, long start, long end) {
Long count = redisTemplate.opsForZSet().removeRange(key, start, end);
return count == null ? 0L : count;
}
/**
* 获取有序集合成员数量(ZCARD)
*/
public long zCard(String key) {
Long size = redisTemplate.opsForZSet().size(key);
return size == null ? 0L : size;
}
/**
* 统计 score 在 [min, max] 范围内的成员数量(ZCOUNT)
*/
public long zCount(String key, double min, double max) {
Long count = redisTemplate.opsForZSet().count(key, min, max);
return count == null ? 0L : count;
}
}