From bd32782f7f1fa65bf5ab7a482e26c552461464bf Mon Sep 17 00:00:00 2001 From: xiang Date: Sun, 24 Aug 2025 17:18:27 +0800 Subject: [PATCH] feat:redis utils v2 --- .../xservice/cache/service/IRedisService.java | 154 ++++++++++++++++++ .../cache/service/RedisServiceImpl.java | 118 ++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/IRedisService.java b/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/IRedisService.java index 227cfcc..74018b2 100644 --- a/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/IRedisService.java +++ b/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/IRedisService.java @@ -1,9 +1,13 @@ package com.xiang.xservice.cache.service; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; public interface IRedisService { + /* ============================================= String数据类型 ============================================= */ + /** * SET String 数据类型key * @param key key @@ -78,4 +82,154 @@ public interface IRedisService { * @return 是否成功 */ Boolean expire(String group, String key, long timeout, TimeUnit unit); + + /* ============================================= String数据类型 ============================================= */ + + /* ========================== Hash ========================== */ + + /** + * SET HASH数据结构 + * @param key key + * @param field hash集合字段 + * @param value hash集合值 + */ + void hSet(String key, String field, Object value); + /** + * SET HASH数据结构 + * @param group 项目 + * @param key key + * @param field hash集合字段 + * @param value hash集合值 + */ + void hSet(String group, String key, String field, Object value); + + /** + * GET HASH数据结构 + * @param key key + * @param field hash集合字段 + * @return hash集合值 + */ + Object hGet(String key, String field); + /** + * GET HASH数据结构 + * @param group 项目 + * @param key key + * @param field hash集合字段 + * @return hash集合值 + */ + Object hGet(String group, String key, String field); + + /** + * GET HASH数据结构 + * @param key key + * @return key下面所有的值 + */ + Map hGetAll(String key); + + /** + * GET HASH数据结构 + * @param group 项目 + * @param key key + * @return key下面所有的值 + */ + Map hGetAll(String group, String key); + + /** + * DEL HASH数据结构 + * @param key key + * @param fields hash集合字段 + * @return 是否删除 + */ + Boolean hDel(String key, Object... fields); + /** + * DEL HASH数据结构 + * @param group 项目 + * @param key key + * @param fields hash集合字段 + * @return 是否删除 + */ + Boolean hDel(String group, String key, Object... fields); + + /** + * hasKey HASH数据结构 + * @param key key + * @param field hash集合字段 + * @return 是否存在 + */ + Boolean hHasKey(String key, String field); + /** + * hasKey HASH数据结构 + * @param group 项目 + * @param key key + * @param field hash集合字段 + * @return 是否存在 + */ + Boolean hHasKey(String group, String key, String field); + /* ========================== Hash ========================== */ + + /* ========================== 分布式锁 ========================== */ + + /** + * 尝试获取分布式锁 + * @param key 锁的key + * @param value 唯一标识(一般用UUID区分客户端) + * @param timeout 锁过期时间 + * @param unit 时间单位 + * @return 是否成功 + */ + Boolean tryLock(String key, String value, long timeout, TimeUnit unit); + /** + * 尝试获取分布式锁 + * @param group 项目组 + * @param key 锁的key + * @param value 唯一标识(一般用UUID区分客户端) + * @param timeout 锁过期时间 + * @param unit 时间单位 + * @return 是否成功 + */ + Boolean tryLock(String group, String key, String value, long timeout, TimeUnit unit); + /** + * 释放分布式锁(只能释放自己加的锁) + * @param key 锁的key + * @param value 唯一标识(必须跟加锁时一致) + * @return 是否成功释放 + */ + Boolean unlock(String key, String value); + /** + * 释放分布式锁(只能释放自己加的锁) + * @param group 项目组 + * @param key 锁的key + * @param value 唯一标识(必须跟加锁时一致) + * @return 是否成功释放 + */ + Boolean unlock(String group, String key, String value); + /** + * 释放分布式锁(只能释放自己加的锁) + * @param key 锁的key + * @param value 唯一标识(必须跟加锁时一致) + * @return 是否成功释放 + */ + Boolean unlockLura(String key, String value); + /** + * 释放分布式锁(只能释放自己加的锁) + * @param group 项目组 + * @param key 锁的key + * @param value 唯一标识(必须跟加锁时一致) + * @return 是否成功释放 + */ + Boolean unlockLura(String group, String key, String value); + /* ========================== 分布式锁 ========================== */ + + /* ========================== Lura脚本执行 ========================== */ + /** + * 执行Lua脚本 + * @param script 脚本内容 + * @param keys KEYS参数 + * @param args ARGV参数 + * @param resultType 返回类型 + * @param 返回类型泛型 + * @return 执行结果 + */ + T executeLua(String script, List keys, List args, Class resultType); + /* ========================== Lura脚本执行 ========================== */ } diff --git a/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/RedisServiceImpl.java b/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/RedisServiceImpl.java index fc91a26..8c2cf3e 100644 --- a/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/RedisServiceImpl.java +++ b/xservice-cache-starter/src/main/java/com/xiang/xservice/cache/service/RedisServiceImpl.java @@ -1,10 +1,16 @@ package com.xiang.xservice.cache.service; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; @Service @@ -61,6 +67,118 @@ public class RedisServiceImpl implements IRedisService { return redisTemplate.expire(buildKey(group, key), timeout, unit); } + @Override + public void hSet(String key, String field, Object value) { + redisTemplate.opsForHash().put(buildKey(group, key), field, value); + } + + @Override + public void hSet(String group, String key, String field, Object value) { + redisTemplate.opsForHash().put(buildKey(group, key), field, value); + } + + @Override + public Object hGet(String key, String field) { + return redisTemplate.opsForHash().get(buildKey(group, key), field); + } + + @Override + public Object hGet(String group, String key, String field) { + return redisTemplate.opsForHash().get(buildKey(group, key), field); + } + + @Override + public Map hGetAll(String key) { + return redisTemplate.opsForHash().entries(buildKey(group, key)); + } + + @Override + public Map hGetAll(String group, String key) { + return redisTemplate.opsForHash().entries(buildKey(group, key)); + } + + @Override + public Boolean hDel(String key, Object... fields) { + return redisTemplate.opsForHash().delete(buildKey(group, key), fields) > 0; + } + + @Override + public Boolean hDel(String group, String key, Object... fields) { + return redisTemplate.opsForHash().delete(buildKey(group, key), fields) > 0; + } + + @Override + public Boolean hHasKey(String key, String field) { + return redisTemplate.opsForHash().hasKey(buildKey(group, key), field); + } + + @Override + public Boolean hHasKey(String group, String key, String field) { + return redisTemplate.opsForHash().hasKey(buildKey(group, key), field); + } + + @Override + public Boolean tryLock(String key, String value, long timeout, TimeUnit unit) { + return tryLock(group, key, value, timeout, unit); + } + + @Override + public Boolean tryLock(String group, String key, String value, long timeout, TimeUnit unit) { + String redisKey = buildKey(group, key); + Boolean success = redisTemplate.opsForValue() + .setIfAbsent(redisKey, value, timeout, unit); + return Boolean.TRUE.equals(success); + } + + @Override + public Boolean unlock(String key, String value) { + return unlock(group, key, value); + } + + @Override + public Boolean unlock(String group, String key, String value) { + if (hasKey(buildKey(group, key), value)) { + String val = (String) get(buildKey(group, key), value); + if (StringUtils.equals(val, value)) { + return delKey(group, key); + } + } + return Boolean.FALSE; + } + + @Override + public Boolean unlockLura(String key, String value) { + return unlockLura(group, key, value); + } + + @Override + public Boolean unlockLura(String group, String key, String value) { + String redisKey = buildKey(group, key); + + String luaScript = + "if redis.call('get', KEYS[1]) == ARGV[1] " + + "then return redis.call('del', KEYS[1]) " + + "else return 0 end"; + + Long result = executeLua( + luaScript, + Collections.singletonList(redisKey), + Collections.singletonList(value), + Long.class + ); + + return Objects.nonNull(result) && result > 0; + } + + @Override + public T executeLua(String script, List keys, List args, Class resultType) { + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptText(script); + redisScript.setResultType(resultType); + + return redisTemplate.execute(redisScript, keys, args.toArray()); + } + private String buildKey(String group, String key) { return String.format("%s:%s", group, key); }