赞
踩
Redis的单线程服务模式,命令keys会阻塞正常的业务请求。
如果你一次keys匹配的数量过多或者在del的时候遇到大key,都会直接导致业务的不可用,甚至造成redis宕机的风险。
删除
//删除所有以U:INFO:开头的key
Set<String> keys1 = redisTemplate.keys("U:INFO:" + "*");
if (StringUtil.isNotNull(keys)) {
redisTemplate.delete(keys);
}
查询
// *号 必须要加,否则无法模糊查询
//String prefix = "ofc-pincode-"+ pincode + "-*";
// 批量获取所有的key
Set<String> keys = redisTemplate.keys(prefix);
List<MyObject> myObjectListRedis = redisTemplate.opsForValue().multiGet(keys);
List<MyObject> myObjectList = JSON.parseArray(myObjectListRedis.toString(), MyObject.class);
log.info("myObjectList:{}",myObjectList.toString());
类似的SCAN命令,对于Redis不同的数据类型还有另外几个SSCAN、HSCAN和ZSCAN,使用方法类似。
案例1
/** * redis扩展工具 */ public abstract class RedisHelper { private static Logger logger = LoggerFactory.getLogger(RedisHelper.class); /** * scan 实现 * @param redisTemplate redisTemplate * @param pattern 表达式,如:abc*,找出所有以abc开始的键 */ public static Set<String> scan(RedisTemplate<String, Object> redisTemplate, String pattern) { return redisTemplate.execute((RedisCallback<Set<String>>) connection -> { Set<String> keysTmp = new HashSet<>(); try (Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder() .match(pattern) .count(10000).build())) { while (cursor.hasNext()) { keysTmp.add(new String(cursor.next(), "Utf-8")); } } catch (Exception e) { logger.error(e.getMessage(), e); throw new RuntimeException(e); } return keysTmp; }); } }
SCAN 命令及其相关的 SSCAN 命令、 HSCAN 命令和 ZSCAN 命令都用于增量地迭代 ,它们每次执行都只会返回少量元素,不会阻塞服务器, 所以这些命令可以用于生产环境, 而不会出现像 KEYS 命令、 SMEMBERS 命令带来的问题。
SCAN一样有它自己的问题:
1.因为是分段获取key,所以它会多次请求redis服务器,这样势必取同样的key,scan耗时更长。
2.在对键进行增量式迭代的过程中, 键可能会被修改, 所以增量式迭代命令只能对被返回的元素提供有限的保证。
案例2
/** * 模糊匹配前缀删除缓存 * * @param key * @return */ @Override public Response<Void> fuzzyMatchDel(String key) throws CommonException { cacheAsyncTask.fuzzyMatchDel(key); return ResponseUtils.success(); } /** * @description: 缓存服务service实现 */ @Service @Slf4j @EnableAsync public class CacheAsyncTask { @Value("${component.cache.scanCount:100}") private Integer scanCount; @Value("${constant.cache.cacheInEquity:true}") private Boolean cacheInEquity; @Value("${component.cache.prefixCacheName:equity}") private String prefixCacheName; @Autowired private StringRedisTemplate stringRedisTemplate; public static final String SPACER = "::"; public static final String WILDCARD = "*"; @Async("asyncTaskExecutor") public void fuzzyMatchDel(String key) throws CommonException { log.info("fuzzyMatchDel删除开始,key前缀:{}", key); long beginTime = System.currentTimeMillis(); // 校验传入的prefix this.regularCheck(key); // 通过spring-redis关于redis:scan命令相关api非阻塞查询缓存结果 Set<String> keySet = stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> { Set<String> binaryKeys = new HashSet<>(); ScanOptions scanOptions = new ScanOptions.ScanOptionsBuilder().match(key).count(scanCount).build(); Cursor<byte[]> cursor = connection.scan(scanOptions); while (cursor.hasNext()) { binaryKeys.add(RedisSerializer.string().deserialize(cursor.next())); } cursor.close(); return binaryKeys; }); List<String> delFailKeys = new ArrayList<>(); Iterator<String> it = keySet.iterator(); while (it.hasNext()) { // 当前开发测试环境的redis版本不支持非阻塞删除unlink命令 String keyNext = it.next(); Boolean success = stringRedisTemplate.delete(keyNext); if (!success) { delFailKeys.add(key); } } long seconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - beginTime); if (delFailKeys.isEmpty()) { log.info("fuzzyMatchDel删除的keys:{},共{}个key,耗时{}秒", keySet, keySet.size(), seconds); return; } log.info("fuzzyMatchDel删除失败,扫描到的keys:{},删除失败的keys:{},耗时{}秒", keySet, delFailKeys, seconds); } /** * 对传入的key前缀进行校验 * * @param prefix * @throws CommonException */ private void regularCheck(String prefix) throws CommonException { if (cacheInEquity && !prefix.startsWith(prefixCacheName + SPACER)) { // 开启了只能删除权益宝工程创建的缓存 throw ExceptionUtils.create(EquityException.EQUITY_CACHE_PREFIX_ILLEGAL); } if (!prefix.endsWith(WILDCARD)) { // 接口只做模糊匹配删除一类前缀的key throw ExceptionUtils.create(EquityException.EQUITY_CACHE_PREFIX_ILLEGAL); } } }
参考文章
https://www.cnblogs.com/37Y37/p/11037923.html
https://blog.csdn.net/qq_42643690/article/details/106234530
https://javazhiyin.blog.csdn.net/article/details/104890232
https://www.cnblogs.com/thiaoqueen/p/10919538.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。