提交 63f220ac 编写于 作者: 如梦技术's avatar 如梦技术 🐛

mica-redis 优化 ICacheKey 和 scan。

上级 40516d95
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
- :sparkles: mica-jetcache 完善 metrics 待续 #37 #I3PX2K - :sparkles: mica-jetcache 完善 metrics 待续 #37 #I3PX2K
- :sparkles: mica-caffeine 添加不支持自定义 Caffeine bean 提示。 - :sparkles: mica-caffeine 添加不支持自定义 Caffeine bean 提示。
- :sparkles: mica-core R 添加 throwOn 系列方法。 - :sparkles: mica-core R 添加 throwOn 系列方法。
- :sparkles: mica-redis 优化 ICacheKey 和 scan。
- :bug: mica-logging 修复 LoggingInitializer Spring boot 2.4.x 失效的问题。 - :bug: mica-logging 修复 LoggingInitializer Spring boot 2.4.x 失效的问题。
- :arrow_up: 升级 druid 到 1.2.6 - :arrow_up: 升级 druid 到 1.2.6
......
...@@ -23,16 +23,17 @@ ...@@ -23,16 +23,17 @@
| 2.4.5 | mica 2.4.x | 2.4.x | 2020 | | 2.4.5 | mica 2.4.x | 2.4.x | 2020 |
| 2.1.1-GA | mica 2.0.x~2.1.x | 2.2.x ~ 2.3.x | Hoxton | | 2.1.1-GA | mica 2.0.x~2.1.x | 2.2.x ~ 2.3.x | Hoxton |
## 版本号说明
`release` 版本号格式为 `x.x.x`, 基本上保持跟 `Spring boot` 一致。
`snapshots` 版本号格式为 `x.x.x-SNAPSHOT``snapshots` 版每次 `push` 后会自动构建。
## mica 生态 ## mica 生态
- mica-auto (Spring boot starter 利器): https://gitee.com/596392912/mica-auto - mica-auto (Spring boot starter 利器): https://gitee.com/596392912/mica-auto
- mica-weixin(jfinal weixin 的 spring boot starter)https://gitee.com/596392912/mica-weixin - mica-weixin(jfinal weixin 的 spring boot starter): https://gitee.com/596392912/mica-weixin
- mica-mqtt(基于 t-io 实现的 mqtt组件)https://gitee.com/596392912/mica-mqtt - mica-mqtt(基于 t-io 实现的 mqtt组件): https://gitee.com/596392912/mica-mqtt
- Spring cloud 微服务 http2 方案(h2c): https://gitee.com/596392912/spring-cloud-java11 - Spring cloud 微服务 http2 方案(h2c): https://gitee.com/596392912/spring-cloud-java11
- mica-security(mica权限系统 vue 改造中): https://gitee.com/596392912/mica-security
## 版本号说明
`release` 版本号格式为 `x.x.x-GA`,响应 `冷神` 的吐槽,改短了一点。
`snapshots` 版本号格式为 `x.x.x-SNAPSHOT``snapshots` 版每次提交后会自动构建。
## 已知问题 ## 已知问题
lombok 生成的 method 问题:https://github.com/rzwitserloot/lombok/issues/1861 lombok 生成的 method 问题:https://github.com/rzwitserloot/lombok/issues/1861
...@@ -69,7 +70,6 @@ LGPL 是 GPL 的一个为主要为类库使用设计的开源协议。和 GPL ...@@ -69,7 +70,6 @@ LGPL 是 GPL 的一个为主要为类库使用设计的开源协议。和 GPL
* `bladex` 完整的线上解决方案(企业生产必备):https://bladex.vip * `bladex` 完整的线上解决方案(企业生产必备):https://bladex.vip
## 相关链接 ## 相关链接
* `示例项目`[https://github.com/lets-mica/mica-example](https://github.com/lets-mica/mica-example)
* mica 源码 Github:[https://github.com/lets-mica](https://github.com/lets-mica) * mica 源码 Github:[https://github.com/lets-mica](https://github.com/lets-mica)
* mica 源码 Gitee(码云):[https://gitee.com/596392912/mica](https://gitee.com/596392912/mica) * mica 源码 Gitee(码云):[https://gitee.com/596392912/mica](https://gitee.com/596392912/mica)
* mica 性能压测:[https://github.com/lets-mica/mica-jmh](https://github.com/lets-mica/mica-jmh) * mica 性能压测:[https://github.com/lets-mica/mica-jmh](https://github.com/lets-mica/mica-jmh)
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
![数学验证码02](../docs/images/0702.m.jpg) ![数学验证码02](../docs/images/0702.m.jpg)
![随机数验证码03](../docs/images/0703.r.jpg) ![随机数验证码03](../docs/images/0703.r.jpg)
![随机数验证码04](../docs/images/0703.r.jpg) ![随机数验证码04](../docs/images/0704.r.jpg)
## 功能和特点 ## 功能和特点
1. 验证码生成 1. 验证码生成
......
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
package net.dreamlu.mica.redis.cache; package net.dreamlu.mica.redis.cache;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString; import lombok.ToString;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
...@@ -30,20 +30,22 @@ import java.time.Duration; ...@@ -30,20 +30,22 @@ import java.time.Duration;
*/ */
@Getter @Getter
@ToString @ToString
@AllArgsConstructor @RequiredArgsConstructor
public class CacheKey { public class CacheKey {
/** /**
* redis key * redis key
*/ */
private String key; private final String key;
/** /**
* 超时时间 秒 * 超时时间 秒
*/ */
@Nullable @Nullable
private Duration expire; private final Duration expire;
public CacheKey(String key) { public CacheKey(String key) {
this.key = key; this(key, null);
} }
} }
...@@ -53,15 +53,23 @@ public interface ICacheKey { ...@@ -53,15 +53,23 @@ public interface ICacheKey {
* @param suffix 参数 * @param suffix 参数
* @return cache key * @return cache key
*/ */
default CacheKey getKey(Object... suffix) { default String getKeyStr(Object... suffix) {
String prefix = this.getPrefix(); String prefix = this.getPrefix();
// 拼接参数 // 拼接参数
String key;
if (ObjectUtil.isEmpty(suffix)) { if (ObjectUtil.isEmpty(suffix)) {
key = prefix; return prefix;
} else {
key = prefix.concat(StringUtil.join(suffix, StringPool.COLON));
} }
return prefix.concat(StringUtil.join(suffix, StringPool.COLON));
}
/**
* 组装 cache key
*
* @param suffix 参数
* @return cache key
*/
default CacheKey getKey(Object... suffix) {
String key = this.getKeyStr(suffix);
Duration expire = this.getExpire(); Duration expire = this.getExpire();
return expire == null ? new CacheKey(key) : new CacheKey(key, expire); return expire == null ? new CacheKey(key) : new CacheKey(key, expire);
} }
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
package net.dreamlu.mica.redis.cache; package net.dreamlu.mica.redis.cache;
import lombok.Getter; import lombok.Getter;
import net.dreamlu.mica.core.tuple.Pair;
import net.dreamlu.mica.core.utils.CollectionUtil; import net.dreamlu.mica.core.utils.CollectionUtil;
import net.dreamlu.mica.core.utils.Exceptions; import net.dreamlu.mica.core.utils.Exceptions;
import org.springframework.data.redis.core.*; import org.springframework.data.redis.core.*;
...@@ -97,10 +96,10 @@ public class MicaRedisCache { ...@@ -97,10 +96,10 @@ public class MicaRedisCache {
/** /**
* Set the {@code value} and expiration {@code timeout} for {@code key}. * Set the {@code value} and expiration {@code timeout} for {@code key}.
* *
* @param key must not be {@literal null}. * @param key must not be {@literal null}.
* @param value must not be {@literal null}. * @param value must not be {@literal null}.
* @param timeout the key expiration timeout. * @param timeout the key expiration timeout.
* @param unit must not be {@literal null}. * @param unit must not be {@literal null}.
* @see <a href="https://redis.io/commands/setex">Redis Documentation: SETEX</a> * @see <a href="https://redis.io/commands/setex">Redis Documentation: SETEX</a>
*/ */
public void setEx(String key, Object value, long timeout, TimeUnit unit) { public void setEx(String key, Object value, long timeout, TimeUnit unit) {
...@@ -215,63 +214,61 @@ public class MicaRedisCache { ...@@ -215,63 +214,61 @@ public class MicaRedisCache {
} }
/** /**
* redis scan * redis scan,count 默认 100
* *
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @return 扫描结果 * @return 扫描结果
*/ */
public Set<String> scan(@Nullable String pattern) { public Set<String> scan(String pattern) {
final Set<String> keySet = new HashSet<>(); return scan(pattern, 100L);
scan(pattern, keySet::add);
return keySet;
} }
/** /**
* redis scan * redis scan
* *
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @param count 一次扫描的数量 * @param count 一次扫描的数量, redis 默认为 10
* @return 扫描结果 * @return 扫描结果
*/ */
public Pair<Long, Set<String>> scan(@Nullable String pattern, @Nullable Long count) { public Set<String> scan(String pattern, @Nullable Long count) {
final Set<String> keySet = new HashSet<>(); final Set<String> keySet = new HashSet<>();
RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer(); scan(pattern, count, keySet::add);
return redisTemplate.execute((RedisCallback<Pair<Long, Set<String>>>) action -> { return keySet;
ScanOptions.ScanOptionsBuilder builder = ScanOptions.scanOptions()
.match(pattern);
if (count != null) {
builder.count(count);
}
try (Cursor<byte[]> cursor = action.scan(builder.build())) {
cursor.forEachRemaining((item) -> keySet.add(keySerializer.deserialize(item)));
return Pair.create(cursor.getPosition(), keySet);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
});
} }
/** /**
* redis scan * redis scan, count 默认 100
* *
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @param consumer 消费者 * @param consumer 消费者
* @return 扫描结果 * @return 扫描结果
*/ */
public void scan(@Nullable String pattern, Consumer<String> consumer) { public void scan(String pattern, Consumer<String> consumer) {
scan(pattern, null, consumer); scan(pattern, 100L, consumer);
} }
/** /**
* redis scan * redis scan
* *
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @param count 一次扫描的数量 * @param count 一次扫描的数量
* @param consumer 消费者 * @param consumer 消费者
* @return 扫描结果 * @return 扫描结果
*/ */
public void scan(@Nullable String pattern, @Nullable Long count, Consumer<String> consumer) { public void scan(String pattern, @Nullable Long count, Consumer<String> consumer) {
RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer(); RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
scanBytes(pattern, count, (bytes) -> consumer.accept(keySerializer.deserialize(bytes)));
}
/**
* redis scan
*
* @param pattern 匹配表达式
* @param count 一次扫描的数量
* @param consumer 消费者
* @return 扫描结果
*/
public void scanBytes(String pattern, @Nullable Long count, Consumer<byte[]> consumer) {
redisTemplate.execute((RedisCallback<Object>) action -> { redisTemplate.execute((RedisCallback<Object>) action -> {
ScanOptions.ScanOptionsBuilder builder = ScanOptions.scanOptions() ScanOptions.ScanOptionsBuilder builder = ScanOptions.scanOptions()
.match(pattern); .match(pattern);
...@@ -279,10 +276,7 @@ public class MicaRedisCache { ...@@ -279,10 +276,7 @@ public class MicaRedisCache {
builder.count(count); builder.count(count);
} }
try (Cursor<byte[]> cursor = action.scan(builder.build())) { try (Cursor<byte[]> cursor = action.scan(builder.build())) {
cursor.forEachRemaining((item) -> { cursor.forEachRemaining(consumer);
String redisKey = keySerializer.deserialize(item);
consumer.accept(redisKey);
});
} catch (IOException e) { } catch (IOException e) {
throw Exceptions.unchecked(e); throw Exceptions.unchecked(e);
} }
...@@ -291,66 +285,66 @@ public class MicaRedisCache { ...@@ -291,66 +285,66 @@ public class MicaRedisCache {
} }
/** /**
* redis sscan * redis sscan,count 默认 100
* *
* @param key key * @param key key
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @return 扫描结果 * @return 扫描结果
*/ */
public Set<String> sScan(String key, @Nullable String pattern) { public Set<String> sScan(String key, String pattern) {
final Set<String> keySet = new HashSet<>(); return sScan(key, pattern, 100L);
sScan(key, pattern, keySet::add);
return keySet;
} }
/** /**
* redis sscan * redis sscan
* *
* @param key key * @param key key
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @param count 一次扫描的数量 * @param count 一次扫描的数量
* @return 扫描结果 * @return 扫描结果
*/ */
public Pair<Long, Set<String>> sScan(String key, @Nullable String pattern, @Nullable Long count) { public Set<String> sScan(String key, String pattern, @Nullable Long count) {
final Set<String> keySet = new HashSet<>(); final Set<String> keySet = new HashSet<>();
RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer(); sScan(key, pattern, count, keySet::add);
return redisTemplate.execute((RedisCallback<Pair<Long, Set<String>>>) action -> { return keySet;
ScanOptions.ScanOptionsBuilder builder = ScanOptions.scanOptions()
.match(pattern);
if (count != null) {
builder.count(count);
}
try (Cursor<byte[]> cursor = action.sScan(keySerializer.serialize(key), builder.build())) {
cursor.forEachRemaining((item) -> keySet.add(keySerializer.deserialize(item)));
return Pair.create(cursor.getPosition(), keySet);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
});
} }
/** /**
* redis sscan * redis sscan
* *
* @param key key * @param key key
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @param consumer consumer * @param consumer consumer
* @return 扫描结果 * @return 扫描结果
*/ */
public void sScan(String key, @Nullable String pattern, Consumer<String> consumer) { public void sScan(String key, String pattern, Consumer<String> consumer) {
sScan(key, pattern, null, consumer); sScan(key, pattern, 100L, consumer);
} }
/** /**
* redis sscan * redis sscan
* *
* @param key key * @param key key
* @param pattern 匹配表达式 * @param pattern 匹配表达式
* @param count 一次扫描的数量 * @param count 一次扫描的数量
* @param consumer consumer * @param consumer consumer
* @return 扫描结果
*/
public void sScan(String key, String pattern, @Nullable Long count, Consumer<String> consumer) {
RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
sScanBytes(key, pattern, count, (bytes) -> consumer.accept(keySerializer.deserialize(bytes)));
}
/**
* redis sscan
*
* @param key key
* @param pattern 匹配表达式
* @param count 一次扫描的数量
* @param consumer consumer
* @return 扫描结果 * @return 扫描结果
*/ */
public void sScan(String key, @Nullable String pattern, @Nullable Long count, Consumer<String> consumer) { public void sScanBytes(String key, String pattern, @Nullable Long count, Consumer<byte[]> consumer) {
RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer(); RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
redisTemplate.execute((RedisCallback<Object>) action -> { redisTemplate.execute((RedisCallback<Object>) action -> {
ScanOptions.ScanOptionsBuilder builder = ScanOptions.scanOptions() ScanOptions.ScanOptionsBuilder builder = ScanOptions.scanOptions()
...@@ -359,10 +353,7 @@ public class MicaRedisCache { ...@@ -359,10 +353,7 @@ public class MicaRedisCache {
builder.count(count); builder.count(count);
} }
try (Cursor<byte[]> cursor = action.sScan(keySerializer.serialize(key), builder.build())) { try (Cursor<byte[]> cursor = action.sScan(keySerializer.serialize(key), builder.build())) {
cursor.forEachRemaining((item) -> { cursor.forEachRemaining(consumer);
String redisKey = keySerializer.deserialize(item);
consumer.accept(redisKey);
});
} catch (IOException e) { } catch (IOException e) {
throw Exceptions.unchecked(e); throw Exceptions.unchecked(e);
} }
...@@ -496,9 +487,9 @@ public class MicaRedisCache { ...@@ -496,9 +487,9 @@ public class MicaRedisCache {
/** /**
* 获取记数器的值,用于初始化获取 incr、incrBy 的值 * 获取记数器的值,用于初始化获取 incr、incrBy 的值
* *
* @param key key * @param key key
* @param seconds 超时时间 * @param seconds 超时时间
* @param loader 加载器 * @param loader 加载器
*/ */
public Long getCounter(String key, long seconds, Supplier<Long> loader) { public Long getCounter(String key, long seconds, Supplier<Long> loader) {
RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer(); RedisSerializer<String> keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
...@@ -524,6 +515,13 @@ public class MicaRedisCache { ...@@ -524,6 +515,13 @@ public class MicaRedisCache {
return redisTemplate.hasKey(key); return redisTemplate.hasKey(key);
} }
/**
* 检查给定 key 是否存在。
*/
public Boolean exists(CacheKey cacheKey) {
return exists(cacheKey.getKey());
}
/** /**
* 从当前数据库中随机返回(不删除)一个 key 。 * 从当前数据库中随机返回(不删除)一个 key 。
*/ */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册