介绍
在redis和caffenie基础上进行二次封装和扩展,更加便利的使用缓存技术。
- redis 序列化扩展了msgpack支持
- jetcache 序列化扩展msgpack和Jackson支持
- 扩展了幂等性和限流功能,限流功能其核心代码来源于 RuoYi-Vue-Plus 代码
依赖库
名称 | 描述 |
---|---|
slf4j-api | |
spring-boot-starter-data-redis | |
jackson-dataformat-msgpack | |
jetcache-starter-redis-lettuce | |
spring-boot-starter-web | |
spring-boot-starter-aop | |
fastjson | |
commons-pool2 | |
zebra-common-util | |
caffeine |
快速开始
引入
xml
<dependency>
<groupId>io.github.zhanghongbin</groupId>
<artifactId>zebra-spring-boot-starter-cache</artifactId>
</dependency>
序列化
提供两种序列化方式:Jackson 和 msgpack。
- redis序列化默认使用Jackson库进行序列化,要使用msgpack序列化配置如下:
yml
zebra:
cache:
serializer:
msgpack:
enabled: true
- jetcache 序列化配置如下:
jetcache具体使用方式参见官网文档,默认为java序列化方式,并扩展了以下两种序列化方式:
msgpack 为 bean:msgPackEncoder和bean:msgPackDecoder
Jackson 为 bean:jacksonEncoder和bean:jacksonDecoder
yml
jetcache:
remote:
default:
valueEncoder: bean:msgPackEncoder
valueDecoder: bean:msgPackDecoder
注: 建议采用一致的序列化方式。
接口幂等性
以注解方式提供给使用者,在controller类的方法上增加 @Idempotent 如下:
java
/**
* 新增客户端管理
*/
@SaCheckPermission("system:client:add")
@Log(title = "新增操作", module = "客户端管理", businessType = BusinessType.INSERT)
@Idempotent
@PostMapping()
public boolean add(@Validated(AddGroup.class) @RequestBody SysClientQuery bo) {
return sysClientService.insertByBo(bo);
}
@Idempotent 参数如下
名称 | 描述 | 是否必填 |
---|---|---|
timeout | 幂等的超时时间,默认为 1 秒 | 否 |
timeUnit | 时间单位,默认为 SECONDS 秒 | 否 |
keyResolver | 使用的 Key 解析器,也就是存放到redis中的key,默认为DefaultIdempotentKeyResolver.class | 否 |
keyArg | 使用的 Key 参数, 如果keyResolver 使用ExpressionIdempotentKeyResolver.class 此参数需要填写 | 否 |
keyResolver解析器,框架提供 DefaultIdempotentKeyResolver和ExpressionIdempotentKeyResolver两种,如果需要自定义解析器需要实现 IdempotentKeyResolver 接口
流量控制
以注解方式提供给使用者,在controller类的方法上增加 @RateLimiter 如下:
java
/**
* 邮箱验证码
*
* @param email 邮箱
*/
@Validated
@RateLimiter(key = "#email", time = 60, count = 1)
@GetMapping("/email/code")
public void getEmailCode(@NotBlank(message = "邮箱不能为空") String email) {
if (mailCaptchaHandler != null) {
boolean flag = mailCaptchaHandler.build(email.trim());
if (!flag) {
R.failed("邮箱验证码发送异常,请稍后再试!");
}
} else {
R.failed("当前系统没有开启邮箱功能!");
}
}
@RateLimiter 参数如下
名称 | 描述 | 是否必填 |
---|---|---|
key | 限流key,支持使用Spring el表达式来动态获取方法上的参数值, 格式类似于 #code.id 或 #code | 否 |
time | 限流时间,单位秒,默认为60秒 | 否 |
count | 限流次数,默认为100 | 否 |
limitType | 限流类型,默认为 LimitType.DEFAULT 全局 , LimitType.IP ip限制 | 否 |
jetcache集成
采用 jetcache 开源库,配置如下: ${spring.redis.password} 代表引用redis配置密码
yml
jetcache:
areaInCacheName: false
local:
default:
type: caffeine
keyConvertor: fastjson2
remote:
default:
type: redis.lettuce
keyConvertor: fastjson2
valueEncoder: bean:msgPackEncoder
valueDecoder: bean:msgPackDecoder
uri: redis://${spring.redis.password}@${spring.redis.host}:${spring.redis.port}/
在 application 启动类上增加 @EnableMethodCache(basePackages = "") 注解 ,其它注解使用看相关文档 https://github.com/alibaba/jetcache
实用工具
- CacheUtil 对 jetcache的封装,提供以下静态方法
名称 | 参数 | 描述 |
---|---|---|
<T> Cache<String, T> getCache(String cacheName) | 缓存名称 | 根据缓存名称获取缓存对象 |
<T> T get(String cacheName, Object key) | 缓存名称,key值 | 根据缓存和key获取缓存值 |
<T> T get(String cacheName, Object key) | 缓存名称,key值 | 根据缓存和key获取缓存值 |
put(String cacheName, Object key, Object value, Duration duration, CacheType cacheType) | 缓存名称,key值,内容,有效期,缓存类型 | 放入缓存 |
put(String cacheName, Object key, Object value, CacheType cacheType) | 缓存名称,key值,内容,缓存类型 | 放入缓存 |
remove(String cacheName, Object key) | 缓存名称,key值, | 删除缓存内容 |
- RedisUtil 对 redis的封装,提供以下静态方法
java
package org.zebra.cache.util;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.zebra.cache.ext.mq.RedisMessage;
import java.time.Duration;
import java.util.*;
/**
* redis 工具类
*
*/
public final class RedisUtil {
private RedisUtil() {}
public static RedisTemplate<String, Object> getRedisTemplate() {
return SpringUtil.getBean("redisTemplate");
}
public static StringRedisTemplate getStringRedisTemplate() {
return SpringUtil.getBean(StringRedisTemplate.class);
}
public static RedisTemplate<String, Object> createRedisTemplate(
RedisSerializer<?> keySerializer, RedisSerializer<?> valueSerializer) {
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(SpringUtil.getBean(RedisConnectionFactory.class));
template.setKeySerializer(keySerializer);
template.setHashKeySerializer(keySerializer);
template.setValueSerializer(valueSerializer);
template.setHashValueSerializer(valueSerializer);
return template;
}
public static StringRedisTemplate createStringRedisTemplate() {
StringRedisTemplate stringTemplate = new StringRedisTemplate();
stringTemplate.setConnectionFactory(SpringUtil.getBean(RedisConnectionFactory.class));
stringTemplate.afterPropertiesSet();
return stringTemplate;
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @param <T> value 泛型
* @param value 值
*/
public static <T> void setCacheObject(RedisTemplate redisTemplate, final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,保留当前对象 TTL 有效期
*
* @param redisTemplate redisTemplate
* @param key key
* @param <T> value
* @param value 值
*/
public static <T> void setCacheObjectKeepTtl(RedisTemplate redisTemplate, final String key, final T value) {
redisTemplate.opsForValue().set(key, value, 0);
}
/**
* 如果不存在则设置 并返回 true 如果存在则返回 false
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @param <T> value 缓存的值
* @param value 值
* @return 成功或失败
*/
public static <T> boolean setObjectIfAbsent(RedisTemplate redisTemplate, final String key, final T value) {
return redisTemplate.opsForValue().setIfAbsent(key, value);
}
/**
* 如果存在则设置 并返回 true 如果存在则返回 false
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @param value 缓存的值
* @param <T> 泛型
* @return 成功或失败
*/
public static <T> boolean setObjectIfPresent(RedisTemplate redisTemplate, final String key, final T value) {
return redisTemplate.opsForValue().setIfPresent(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @param value 缓存的值
* @param <T> 泛型
* @param duration 时间
*/
public static <T> void setCacheObject(
RedisTemplate redisTemplate, final String key, final T value, final Duration duration) {
redisTemplate.opsForValue().set(key, value, duration);
}
/**
* 如果不存在则设置 并返回 true 如果存在则返回 false
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @param <T> 缓存的值
* @param value 值
* @param duration 超时时间
* @return 成功或失败
*/
public static <T> boolean setObjectIfAbsent(
RedisTemplate redisTemplate, final String key, final T value, final Duration duration) {
return redisTemplate.opsForValue().setIfAbsent(key, value, duration);
}
/**
* 如果存在则设置 并返回 true 如果存在则返回 false
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @param <T> 缓存的值
* @param duration 超时时间
* @param value 值
* @return 成功或失败
*/
public static <T> boolean setObjectIfPresent(
RedisTemplate redisTemplate, final String key, final T value, final Duration duration) {
return redisTemplate.opsForValue().setIfPresent(key, value, duration);
}
/**
* 获取缓存对象
*
* @param redisTemplate redisTemplate
* @param key key
* @param <T> 泛型
* @return 泛型对象
*/
public static <T> T getCacheObject(RedisTemplate redisTemplate, final String key) {
return (T) redisTemplate.opsForValue().get(key);
}
/**
* 删除单个对象
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @return true ,false
*/
public static boolean delete(RedisTemplate redisTemplate, final String key) {
return redisTemplate.delete(key);
}
/**
* 删除集合对象
*
* @param redisTemplate redisTemplate
* @param collection 多个对象
*/
public static void delete(RedisTemplate redisTemplate, final Collection<String> collection) {
redisTemplate.delete(collection);
}
/**
* 检查缓存对象是否存在
*
* @param redisTemplate redisTemplate
* @param key 缓存的键值
* @return true ,false
*/
public static boolean exist(RedisTemplate redisTemplate, final String key) {
return redisTemplate.hasKey(key);
}
public static boolean exist(RedisTemplate redisTemplate, String... keys) {
Long number = redisTemplate.countExistingKeys(Arrays.asList(keys));
return number == null ? false : keys.length == number.intValue() ? true : false;
}
/**
* 设置有效时间
*
* @param redisTemplate redisTemplate
* @param key Redis键
* @param duration 超时时间
* @return true=设置成功;false=设置失败
*/
public static boolean expire(RedisTemplate redisTemplate, final String key, final Duration duration) {
return redisTemplate.expire(key, duration);
}
/**
* 设置 key 的过期时间到指定的日期
*
* @param redisTemplate redisTemplate
* @param key 待修改过期时间的 key
* @param date 过期时间
* @return 修改成功返回 true
*/
public static boolean expireAt(RedisTemplate redisTemplate, String key, Date date) {
return Boolean.TRUE.equals(redisTemplate.expireAt(key, date));
}
/**
* 获得key剩余存活时间
*
* @param redisTemplate redisTemplate
* @param key 缓存键值
* @return 剩余存活时间 秒
*/
public static long getTimeToLive(RedisTemplate redisTemplate, final String key) {
return redisTemplate.getExpire(key);
}
/**
* 获取所有符合指定表达式的 key
*
* @param redisTemplate redisTemplate
* @param pattern 表达式
* @return key集合
*/
public static Set<String> keys(RedisTemplate redisTemplate, String pattern) {
return redisTemplate.keys(pattern);
}
// -------------------------- list command start --------------------------------
/**
* 获取指定 list 指定索引位置的元素
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param index 索引位置,0 表示第一个元素,负数索引用于指定从尾部开始计数,-1 表示最后一个元素,-2 倒数第二个
* @param <T> 泛型对象
* @return 返回对应索引位置的元素,不存在时为 null
*/
public static <T> T lIndex(RedisTemplate redisTemplate, String key, long index) {
return (T) redisTemplate.opsForList().index(key, index);
}
/**
* 获取指定 list 的元素个数即长度
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @return 返回 list 的长度,当 list 不存在时返回 0
*/
public static long lSize(RedisTemplate redisTemplate, String key) {
return redisTemplate.opsForList().size(key);
}
/**
* 以原子方式返回并删除列表的第一个元素,例如列表包含元素 "a", "b", "c" LPOP 操作将返回 ”a“ 并将其删除,list 中元素变为 ”b“, "c"
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param <T> 泛型对象
* @return 返回弹出的元素
*/
public static <T> T lPop(RedisTemplate redisTemplate, String key) {
return (T) redisTemplate.opsForList().leftPop(key);
}
/**
* 以原子方式返回并删除列表的多个元素
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param count 弹出的个数
* @param <T> 泛型对象
* @return 返回弹出的元素列表,key 不存在时为 null
*/
public static <T> List<T> lPop(RedisTemplate redisTemplate, String key, long count) {
return (List<T>) redisTemplate.opsForList().leftPop(key, count);
}
/**
* 该命令返回 list 匹配元素的索引。它会从头到尾扫描列表,寻找 “element” 的第一个匹配项。
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param element 查找的元素
* @param <T> 泛型对象
* @return 指定元素正向第一个匹配项的索引,如果找不到,返回 null
*/
public static <T> Long lIndexOf(RedisTemplate redisTemplate, String key, T element) {
return redisTemplate.opsForList().indexOf(key, element);
}
/**
* 将指定的元素插入 list 的头部,若 list 不存在,则先指向创建一个空的 list
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param elements 插入的元素
* @param <T> 泛型对象
* @return 插入后的 list 长度
*/
public static <T> long lPush(RedisTemplate redisTemplate, String key, T... elements) {
return redisTemplate.opsForList().leftPushAll(key, elements);
}
/**
* 获取 list 指定 offset 间的元素。
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param start begin offset, 从 0 开始,0 表示列表第一个元素,也可以为负数,表示从 list 末尾开始的偏移量, -1
* 是列表最后第一个元素
* @param end end offset,值规则 同 start
* @param <T> 泛型对象
* @return 元素集合
*/
public static <T> List<T> lRange(RedisTemplate redisTemplate, String key, long start, long end) {
return (List<T>) redisTemplate.opsForList().range(key, start, end);
}
/**
* 删除 list 中的元素
*
* @param redisTemplate redisTemplate
* <p>
* count > 0: 从 list 头部向尾部查找并删除 n 个和指定值相等的元素,n 为 count
* count < 0: 从 list 尾部向头部查找并删除 n 个和指定值相等的元素,n 为 count 的绝对值
* count = 0: 删除 list 中所有和指定值相等的元素
* @param key list 的 key
* @param count 删除的数量以及规则
* @param value 待删除的元素值
* @param <T> 泛型对象
* @return 移除元素的数量
*/
public static <T> long lRemove(RedisTemplate redisTemplate, String key, long count, T value) {
return redisTemplate.opsForList().remove(key, count, value);
}
/**
* 将 list 指定 index 位置的元素设置为当前值
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param index 索引位置,0 表示第一个元素,负数索引用于指定从尾部开始计数,-1 表示最后一个元素,-2 倒数第二个
* @param value 值
* @param <T> 泛型对象
*/
public static <T> void lSet(RedisTemplate redisTemplate, String key, long index, T value) {
redisTemplate.opsForList().set(key, index, value);
}
/**
* 裁剪 list,只保留 start 到 end 之间的元素值,包含 start 和 end
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param start 开始索引位置,0 表示第一个元素,负数索引用于指定从尾部开始计数,-1 表示最后一个元素,-2 倒数第二个
* @param end 结束的索引位置
*/
public static void lTrim(RedisTemplate redisTemplate, String key, long start, long end) {
redisTemplate.opsForList().trim(key, start, end);
}
/**
* 以原子方式返回并删除列表的最后一个元素。
*
* @param redisTemplate redisTemplate
* <p>
* 例如 list 包含元素 "a"、"b"、"c", RPOP 操作将返回 ”c“ 并将其删除,list 中元素变为 ”a“, "b"
* @param key list 的 key
* @param <T> 泛型对象
* @return 弹出的元素
*/
public static <T> T lRightPop(RedisTemplate redisTemplate, String key) {
return (T) redisTemplate.opsForList().rightPop(key);
}
/**
* 从 list 尾部,以原子方式返回并删除列表中指定数量的元素。
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param count 待弹出的元素数量
* @param <T> 泛型对象
* @return 弹出的元素集合
*/
public static <T> List<T> lRightPop(RedisTemplate redisTemplate, String key, long count) {
return (List<T>) redisTemplate.opsForList().rightPop(key, count);
}
/**
* 将指定的值插入 list 的尾部,若 list 不存在,则先指向创建一个空的 list
*
* @param redisTemplate redisTemplate
* @param key list 的 key
* @param values 插入的元素
* @param <T> 泛型对象
* @return 插入后的 list 长度
*/
public static <T> long LRightPush(RedisTemplate redisTemplate, String key, T... values) {
return redisTemplate.opsForList().rightPushAll(key, values);
}
// ---------------------- hash command start ---------------
/**
* 删除指定 hash 的 fields
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @param fields hash 元素的 field 集合
* @return 删除的 field 数量
*/
public static long hDelete(RedisTemplate redisTemplate, String key, String... fields) {
return redisTemplate.opsForHash().delete(key, fields);
}
/**
* 判断指定 hash 的 指定 field 是否存在
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @param field 元素的 field
* @return 存在返回 {@code true}, 否则返回 {@code false}
*/
public static boolean hExists(RedisTemplate redisTemplate, String key, String field) {
return redisTemplate.opsForHash().hasKey(key, field);
}
/**
* 获取 hash 中的指定 field 对应的 value 值
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @param field 元素的 field
* @param <T> 泛型对象
* @return 对象
*/
public static <T> T hGet(RedisTemplate redisTemplate, String key, String field) {
return (T) redisTemplate.opsForHash().get(key, field);
}
/**
* 获取 hash 中所有的 fields 和 values, 并已键值对的方式返回
*
* @param redisTemplate redisTemplate
* @param <T> 泛型对象
* @param key hash 的 key
* @return map 对象
*/
public static <T> Map<String, T> hGetAll(RedisTemplate redisTemplate, String key) {
return (Map) redisTemplate.opsForHash().entries(key);
}
/**
* 对 hash 中指定的 field 进行自增若 field 不存在则,先设置为 0 再进行自增,若 hash 不存在则先创建 hash 再进行上述步骤
*
* @param redisTemplate redisTemplate
* @param key key
* @param field field
* @param delta 自增步长
* @return 自增后的 value 值
*/
public static long hIncrBy(RedisTemplate redisTemplate, String key, String field, long delta) {
return redisTemplate.opsForHash().increment(key, field, delta);
}
public static Long hIncrBy(RedisTemplate redisTemplate, String key, String field) {
return hIncrBy(redisTemplate, key, field, 1);
}
/**
* 对 hash 中指定的 field 进行自增若 field 不存在则,先设置为 0 再进行自增,若 hash 不存在则先创建 hash 再进行上述步骤
*
* @param redisTemplate redisTemplate
* @param key key
* @param field field
* @param delta 自增步长
* @return 自增后的 value 值
*/
public static double hIncrByFloat(RedisTemplate redisTemplate, String key, String field, double delta) {
return redisTemplate.opsForHash().increment(key, field, delta);
}
/**
* 返回 hash 中的所有 fields
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @return Set of fields in hash
*/
public static Set<String> hKeys(RedisTemplate redisTemplate, String key) {
return (Set) redisTemplate.opsForHash().keys(key);
}
/**
* 返回 hash 中 fields 的数量
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @return fields size
*/
public static long hSize(RedisTemplate redisTemplate, String key) {
return redisTemplate.opsForHash().size(key);
}
/**
* 返回 hash 中指定 fields 的值集合
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @param <T> 泛型对象
* @return fields value list, 按传入的 fields 顺序排列
*/
public static <T> List<T> hMGet(RedisTemplate redisTemplate, String key, String... fields) {
return (List<T>) redisTemplate.opsForHash().multiGet(key, Arrays.asList(fields));
}
/**
* 修改 hash 中的 field 的值,有则覆盖,无则添加
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @param field field
* @param value value
* @param <T> 泛型对象
*/
public static <T> void hSet(RedisTemplate redisTemplate, String key, String field, T value) {
redisTemplate.opsForHash().put(key, field, value);
}
/**
* 修改 hash 中的 field 的值,有则不进行操作,无则添加
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @param field field
* @param value value
* @param <T> 泛型对象
*/
public static <T> void hSetNx(RedisTemplate redisTemplate, String key, String field, T value) {
redisTemplate.opsForHash().putIfAbsent(key, field, value);
}
/**
* 返回 hash 中的所有 values
*
* @param redisTemplate redisTemplate
* @param key hash 的 key
* @return List of fields in hash
*/
public static <T> List<T> hValues(RedisTemplate redisTemplate, String key) {
return (List<T>) redisTemplate.opsForHash().values(key);
}
// -------------------------- hash command end --------------------------------
// -------------------------- Set command start --------------------------------
/**
* 将指定的 member 添加到 Set 中,如果 Set 中已有该 member 则忽略。如果 Set 不存在,则先创建一个新的 Set,再进行添加
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(1)
*
* @param key Set 的 key
* @param members 添加的成员
* @return 添加到集合中的元素数量,不包括集合中已经存在的所有元素
*/
public static <T> long sAdd(RedisTemplate redisTemplate, String key, T... members) {
return redisTemplate.opsForSet().add(key, members);
}
/**
* 返回 Set 中的元素数,如果 set 不存在则返回 0
* @param redisTemplate redisTemplate
* @param key Set 的 key
* @return The cardinality (number of elements) of the set
* @see <a href="https://redis.io/commands/scard/">SCard Command</a>
*/
public static long sSize(RedisTemplate redisTemplate, String key) {
return redisTemplate.opsForSet().size(key);
}
/**
* 判断指定的值是否是 Set 中的元素
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(1)
*
* @param key Set 的 key
* @param value 待判断的值
* @return 如果是 Set 中的元素返回{@code true}, 否则返回{@code false}
*/
public static <T> boolean sIsMember(RedisTemplate redisTemplate, String key, T value) {
return redisTemplate.opsForSet().isMember(key, value);
}
/**
* 获取 Set 中的所有元素
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(N)
*
* @param key Set 的 key
* @return Set 中的所有元素
*/
public static <T> Set<T> sMembers(RedisTemplate redisTemplate, String key) {
return (Set<T>) redisTemplate.opsForSet().members(key);
}
/**
* 判断指定的值是否是 Set 中的元素
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(N)
*
* @param key Set 的 key
* @param values 待判断的值集合
* @return 一个 Map, key 为待判断的值,value 为结果
*/
public static <T> Map<T, Boolean> sIsMember(RedisTemplate redisTemplate, String key, T... values) {
return (Map<T, Boolean>) redisTemplate.opsForSet().isMember(key, values);
}
/**
* 随机从 Set 中删除一个元素,并返回它,如果 Set 为空,则返回 null
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(1)
*
* @param key Set 的 key
* @return 弹出的元素,或者 null
*/
public static <T> T sPop(RedisTemplate redisTemplate, String key) {
return (T) redisTemplate.opsForSet().pop(key);
}
/**
* 随机从 Set 中返回一个元素,但不删除,如果 Set 为空,则返回 null
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(1)
*
* @param key Set 的 key
* @return 随机选中的元素或者 null
*/
public static <T> T sRandMember(RedisTemplate redisTemplate, String key) {
return (T) redisTemplate.opsForSet().randomMember(key);
}
/**
* 随机从 Set 中返回 count 个元素,但不删除,如果 Set 为空,则返回 null
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(1)
*
* @param key Set 的 key
* @param count 随机返回的元素数量
* @return 随机选中的元素或者 null
*/
public static <T> Set<T> sRandMember(RedisTemplate redisTemplate, String key, long count) {
return (Set<T>) redisTemplate.opsForSet().distinctRandomMembers(key, count);
}
/**
* 从 Set 中删除指定的 member,如果给的值不是 Set 的 member 则不进行操作
* @param redisTemplate redisTemplate
* <p>
* Time complexity O(1)
*
* @param key Set 的 key
* @param members 待删除的成员
* @return The number of members that were removed from the set, not including
* non-existing members
*/
public static <T> long sRemove(RedisTemplate redisTemplate, String key, T... members) {
StringRedisTemplate stringTemplate = new StringRedisTemplate();
return redisTemplate.opsForSet().remove(key, members);
}
}