手写Redis分布式锁+RedisUtil二次封装

server/2024/12/24 3:08:58/

文章目录

    • 1.手写Redis分布式
        • 1.RedisShareLockUtil
        • 2.使用方式
    • 2.RedisUtil二次封装
        • 1.RedisUtil
        • 2.使用案例

1.手写Redis分布式

1.RedisShareLockUtil
package com.sunxiansheng.redis.util;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;@Component
public class RedisShareLockUtil {private static final Logger logger = LoggerFactory.getLogger(RedisShareLockUtil.class);private static final long DEFAULT_TIMEOUT = 10; // 默认超时时间(秒)private static final String DEFAULT_LOCK_NAME_PREFIX = "lock:"; // 默认锁名前缀@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 尝试获取锁* @param lockKey 锁的key* @param timeout 超时时间(秒)* @return 锁的value,用于释放锁*/public String tryLock(String lockKey, long timeout) {String value = UUID.randomUUID().toString();Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, value, timeout, TimeUnit.SECONDS);while (locked == null || !locked) {if (locked == null) {logger.error("尝试获取锁时出现错误,可能是 Redis 连接问题,key: {}", lockKey);} else {logger.warn("获取锁失败,重试中,key: {}", lockKey);}try {Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();logger.error("尝试获取锁时线程被中断,key: {}", lockKey, e);return null;}locked = redisTemplate.opsForValue().setIfAbsent(lockKey, value, timeout, TimeUnit.SECONDS);}logger.info("成功获取锁,key: {}", lockKey);return value;}/*** 释放锁* @param lockKey 锁的key* @param value 锁的value*/public boolean releaseLock(String lockKey, String value) {String scriptText = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";DefaultRedisScript<Long> script = new DefaultRedisScript<>();script.setScriptText(scriptText);script.setResultType(Long.class);Long result = redisTemplate.execute(script, Collections.singletonList(lockKey), value);if (result != null && result > 0) {logger.info("成功释放锁,key: {}", lockKey);return true;} else {if (result == null) {logger.error("释放锁失败,Redis 执行错误,key: {}", lockKey);} else {logger.warn("释放锁失败,锁不存在或锁的值不匹配,key: {}", lockKey);}return false;}}/*** 使用锁执行操作,使用默认超时时间* @param lockKey 锁的key* @param action 要执行的操作*/public void executeWithLock(String lockKey, Runnable action) {executeWithLock(lockKey, DEFAULT_TIMEOUT, action);}/*** 使用锁执行操作* @param lockKey 锁的key* @param timeout 超时时间(秒)* @param action 要执行的操作*/public void executeWithLock(String lockKey, long timeout, Runnable action) {String fullLockKey = DEFAULT_LOCK_NAME_PREFIX + lockKey;String value = tryLock(fullLockKey, timeout);if (value != null) {try {action.run();} finally {releaseLock(fullLockKey, value);}} else {logger.warn("无法获取锁,key: {}", fullLockKey);}}
}
2.使用方式
    @RequestMapping("/testLock")public void testLock() {// 默认超时时间10s,自定义锁名字redisShareLockUtil.executeWithLock("mylock", () -> {// 需要加锁的逻辑});// // 自定义超时时间30s,自定义锁名字redisShareLockUtil.executeWithLock("mylock", 30, () -> {// 需要加锁的逻辑});}

2.RedisUtil二次封装

1.RedisUtil
package com.sunxiansheng.redis.util;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;/*** Description: RedisUtil工具类* @Author sun* @Create 2024/6/5 14:17* @Version 1.0*/
@Component
public class RedisUtil {private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);@Resourceprivate RedisTemplate<String, Object> redisTemplate;private static final String CACHE_KEY_SEPARATOR = ".";/*** 构建缓存key* @param strObjs 多个字符串拼接成缓存key* @return 拼接后的缓存key* @example* <pre>*     String key = redisUtil.buildKey("user", "123");*     System.out.println(key);  // 输出: user.123* </pre>*/public String buildKey(String... strObjs) {return String.join(CACHE_KEY_SEPARATOR, strObjs);}// =============================Common============================/*** 是否存在key* @param key Redis中的key* @return true如果key存在,否则false* @example* <pre>*     boolean exists = redisUtil.exists("myKey");*     System.out.println(exists);* </pre>*/public boolean exists(String key) {return execute(() -> redisTemplate.hasKey(key));}/*** 删除key* @param key Redis中的key* @return true如果删除成功,否则false* @example* <pre>*     boolean deleted = redisUtil.delete("myKey");*     System.out.println(deleted);* </pre>*/public boolean delete(String key) {return execute(() -> redisTemplate.delete(key));}// =============================String============================/*** 设置key-value对* @param key Redis中的key* @param value 要设置的值* @example* <pre>*     redisUtil.set("myKey", "myValue");* </pre>*/public void set(String key, Object value) {execute(() -> {redisTemplate.opsForValue().set(key, value);return null;});}/*** 设置key-value对,并设置过期时间* @param key Redis中的key* @param value 要设置的值* @param timeout 过期时间* @param unit 时间单位* @example* <pre>*     redisUtil.set("myKey", "myValue", 10, TimeUnit.MINUTES);* </pre>*/public void set(String key, Object value, long timeout, TimeUnit unit) {execute(() -> {redisTemplate.opsForValue().set(key, value, timeout, unit);return null;});}/*** 设置key-value对,如果key不存在,则设置成功,并指定过期时间* @param key Redis中的key* @param value 要设置的值* @param timeout 过期时间* @param unit 时间单位* @return true如果设置成功,否则false* @example* <pre>*     boolean result = redisUtil.setIfAbsent("myKey", "myValue", 10, TimeUnit.MINUTES);*     System.out.println(result);* </pre>*/public boolean setIfAbsent(String key, Object value, long timeout, TimeUnit unit) {return execute(() -> redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit));}/*** 获取指定key的值* @param key Redis中的key* @param clazz 值的类型* @return key对应的值* @example* <pre>*     String value = redisUtil.get("myKey", String.class);*     System.out.println(value);* </pre>*/public <T> Optional<T> get(String key, Class<T> clazz) {return Optional.ofNullable(execute(() -> clazz.cast(redisTemplate.opsForValue().get(key))));}/*** 递增* @param key Redis中的key* @param delta 增量* @example* <pre>*     redisUtil.increment("myKey", 1);* </pre>*/public void increment(String key, long delta) {execute(() -> {redisTemplate.opsForValue().increment(key, delta);return null;});}// =============================Hash============================/*** 向hash中存入数据* @param key Redis中的key* @param hashKey hash中的小key* @param value hash中的小value* @example* <pre>*     redisUtil.hPut("myHash", "field1", "value1");* </pre>*/public void hPut(String key, String hashKey, Object value) {execute(() -> {redisTemplate.opsForHash().put(key, hashKey, value);return null;});}/*** 获取hash中的数据* @param key Redis中的key* @param hashKey hash中的小key* @param clazz 值的类型* @return hash中的小value* @example* <pre>*     String value = redisUtil.hGet("myHash", "field1", String.class);*     System.out.println(value);* </pre>*/public <T> Optional<T> hGet(String key, String hashKey, Class<T> clazz) {return Optional.ofNullable(execute(() -> clazz.cast(redisTemplate.opsForHash().get(key, hashKey))));}/*** 获取hash中的所有数据* @param key Redis中的key* @return hash中的所有数据* @example* <pre>*     Map<Object, Object> map = redisUtil.hGetAll("myHash");*     map.forEach((k, v) -> System.out.println(k + ": " + v));* </pre>*/public Optional<Map<Object, Object>> hGetAll(String key) {return Optional.ofNullable(execute(() -> redisTemplate.opsForHash().entries(key)));}/*** 删除hash中的指定字段* @param key Redis中的key* @param hashKey hash中的小key* @example* <pre>*     redisUtil.hDelete("myHash", "field1");* </pre>*/public void hDelete(String key, Object... hashKey) {execute(() -> {redisTemplate.opsForHash().delete(key, hashKey);return null;});}/*** 获取并删除hash中的所有数据* @param key Redis中的key* @return hash中的所有数据* @example* <pre>*     Map<Object, Object> map =redisUtil.hGetAndDelete(“myHash”);*     map.forEach((k, v) -> System.out.println(k + “: “ + v));* </pre>*/public Optional<Map<Object, Object>> hGetAndDelete(String key) {Map<Object, Object> map = new HashMap<>();try (Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(key, ScanOptions.NONE)) {while (cursor.hasNext()) {Map.Entry<Object, Object> entry = cursor.next();Object hashKey = entry.getKey();Object hashValue = entry.getValue();map.put(hashKey, hashValue);redisTemplate.opsForHash().delete(key, hashKey);}} catch (Exception e) {logger.error("Redis hGetAndDelete error: key={}", key, e);}return Optional.of(map);}
// =============================List============================/*** 向list中左侧推入数据* @param key Redis中的key* @param value list中的值* @example* <pre>*     redisUtil.lPush("myList", "value1");* </pre>*/public void lPush(String key, Object value) {execute(() -> {redisTemplate.opsForList().leftPush(key, value);return null;});}/*** 向list中右侧推入数据* @param key Redis中的key* @param value list中的值* @example* <pre>*     redisUtil.rPush("myList", "value1");* </pre>*/public void rPush(String key, Object value) {execute(() -> {redisTemplate.opsForList().rightPush(key, value);return null;});}/*** 从list中左侧弹出数据* @param key Redis中的key* @param clazz 值的类型* @return list中的值* @example* <pre>*     String value = redisUtil.lPop("myList", String.class).orElse(null);*     System.out.println(value);* </pre>*/public <T> Optional<T> lPop(String key, Class<T> clazz) {return Optional.ofNullable(execute(() -> clazz.cast(redisTemplate.opsForList().leftPop(key))));}/*** 从list中右侧弹出数据* @param key Redis中的key* @param clazz 值的类型* @return list中的值* @example* <pre>*     String value = redisUtil.rPop("myList", String.class).orElse(null);*     System.out.println(value);* </pre>*/public <T> Optional<T> rPop(String key, Class<T> clazz) {return Optional.ofNullable(execute(() -> clazz.cast(redisTemplate.opsForList().rightPop(key))));}/*** 获取list中的指定范围的数据* @param key Redis中的key* @param start 起始位置* @param end 结束位置* @return list中的值* @example* <pre>*     List<Object> list = redisUtil.lRange("myList", 0, -1).orElse(Collections.emptyList());*     list.forEach(System.out::println);* </pre>*/public Optional<List<Object>> lRange(String key, long start, long end) {return Optional.ofNullable(execute(() -> redisTemplate.opsForList().range(key, start, end)));}// =============================Set============================/*** 向set中添加数据* @param key Redis中的key* @param values set中的值* @example* <pre>*     redisUtil.sAdd("mySet", "value1", "value2");* </pre>*/public void sAdd(String key, Object... values) {execute(() -> {redisTemplate.opsForSet().add(key, values);return null;});}/*** 获取set中的所有数据* @param key Redis中的key* @return set中的所有值* @example* <pre>*     Set<Object> set = redisUtil.sMembers("mySet").orElse(Collections.emptySet());*     set.forEach(System.out::println);* </pre>*/public Optional<Set<Object>> sMembers(String key) {return Optional.ofNullable(execute(() -> redisTemplate.opsForSet().members(key)));}/*** 判断set中是否存在指定的值* @param key Redis中的key* @param value set中的值* @return true如果存在,否则false* @example* <pre>*     boolean exists = redisUtil.sIsMember("mySet", "value1").orElse(false);*     System.out.println(exists);* </pre>*/public Optional<Boolean> sIsMember(String key, Object value) {return Optional.ofNullable(execute(() -> redisTemplate.opsForSet().isMember(key, value)));}/*** 从set中随机弹出一个值* @param key Redis中的key* @return set中的值* @example* <pre>*     Object value = redisUtil.sPop("mySet").orElse(null);*     System.out.println(value);* </pre>*/public Optional<Object> sPop(String key) {return Optional.ofNullable(execute(() -> redisTemplate.opsForSet().pop(key)));}/*** 获取set的大小* @param key Redis中的key* @return set的大小* @example* <pre>*     long size = redisUtil.sCard("mySet").orElse(0L);*     System.out.println(size);* </pre>*/public Optional<Long> sCard(String key) {return Optional.ofNullable(execute(() -> redisTemplate.opsForSet().size(key)));}// =============================ZSet============================/*** 向有序集合中添加元素* @param key Redis中的key* @param value 元素的值* @param score 元素的分数* @return true如果添加成功,否则false* @example* <pre>*     boolean added = redisUtil.zAdd("myZSet", "value1", 1.0).orElse(false);*     System.out.println(added);* </pre>*/public Optional<Boolean> zAdd(String key, Object value, double score) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().add(key, value, score)));}/*** 获取有序集合的元素数量* @param key Redis中的key* @return 元素数量* @example* <pre>*     long size = redisUtil.zCard("myZSet").orElse(0L);*     System.out.println(size);* </pre>*/public Optional<Long> zCard(String key) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().size(key)));}/*** 获取有序集合指定范围内的元素* @param key Redis中的key* @param start 起始位置* @param end 结束位置* @return 指定范围内的元素集合* @example* <pre>*     Set<Object> set = redisUtil.zRange("myZSet", 0, -1).orElse(Collections.emptySet());*     set.forEach(System.out::println);* </pre>*/public Optional<Set<Object>> zRange(String key, long start, long end) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().range(key, start, end)));}/*** 删除有序集合中的指定元素* @param key Redis中的key* @param value 要删除的元素* @return 被删除的元素数量* @example* <pre>*     long removed = redisUtil.zRemove("myZSet", "value1").orElse(0L);*     System.out.println(removed);* </pre>*/public Optional<Long> zRemove(String key, Object value) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().remove(key, value)));}/*** 获取有序集合中指定元素的分数* @param key Redis中的key* @param value 元素的值* @return 元素的分数* @example* <pre>*     double score = redisUtil.zScore("myZSet", "value1").orElse(null);*     System.out.println(score);* </pre>*/public Optional<Double> zScore(String key, Object value) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().score(key, value)));}/*** 获取有序集合中指定分数范围内的元素* @param key Redis中的key* @param start 起始分数* @param end 结束分数* @return 指定分数范围内的元素集合* @example* <pre>*     Set<Object> set = redisUtil.zRangeByScore("myZSet”, 0, 100).orElse(Collections.emptySet());*     set.forEach(System.out::println);**/public Optional<Set> zRangeByScore(String key, double start, double end) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().rangeByScore(key, start, end)));}/*** 增加有序集合中指定元素的分数* @param key Redis中的key* @param value 元素的值* @param score 增加的分数* @return 增加后的分数* @example* <pre>*     double newScore = redisUtil.zIncrementScore("myZSet", "value1", 10.0).orElse(null);*     System.out.println(newScore);* </pre>*/public Optional<Double> zIncrementScore(String key, Object value, double score) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().incrementScore(key, value, score)));}/*** 获取有序集合中指定元素的排名* @param key Redis中的key* @param value 元素的值* @return 元素的排名* @example* <pre>*     long rank = redisUtil.zRank("myZSet", "value1").orElse(null);*     System.out.println(rank);* </pre>*/public Optional<Long> zRank(String key, Object value) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().rank(key, value)));}/*** 从有序集合中按分数范围获取成员及其分数* @param key 排行榜的key* @param start 起始位置(包含)* @param end 结束位置(包含)* @return Set<ZSetOperations.TypedTuple < Object>> 每个TypedTuple对象包含以下内容:value: 集合中的成员,score: 成员的分数。* @example* <pre>*     Set<ZSetOperations.TypedTuple<Object>> set = redisUtil.zRangeWithScores("myZSet", 0, 100).orElse(Collections.emptySet());*     set.forEach(tuple -> System.out.println(tuple.getValue() + ": " + tuple.getScore()));* </pre>*/public Optional<Set<ZSetOperations.TypedTuple<Object>>> zRangeWithScores(String key, long start, long end) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().rangeWithScores(key, start, end)));}/*** 获取有序集合中指定分数范围内的成员及其分数* @param key Redis中的key* @param min 最小分数* @param max 最大分数* @return Set<ZSetOperations.TypedTuple < Object>> 每个TypedTuple对象包含以下内容:value: 集合中的成员,score: 成员的分数。* @example* <pre>*     Set<ZSetOperations.TypedTuple<Object>> set = redisUtil.zRangeByScoreWithScores("myZSet", 0, 100).orElse(Collections.emptySet());*     set.forEach(tuple -> System.out.println(tuple.getValue() + ": " + tuple.getScore()));* </pre>*/public Optional<Set<ZSetOperations.TypedTuple<Object>>> zRangeByScoreWithScores(String key, double min, double max) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max)));}/*** 获取有序集合中指定成员的分数范围排名* @param key Redis中的key* @param value 成员的值* @return 成员的分数排名* @example* <pre>*     long rank = redisUtil.zRevRank("myZSet", "value1").orElse(null);*     System.out.println(rank);* </pre>*/public Optional<Long> zRevRank(String key, Object value) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().reverseRank(key, value)));}/*** 获取有序集合中指定分数范围内的元素数量* @param key Redis中的key* @param min 最小分数* @param max 最大分数* @return 元素数量* @example* <pre>*     long count = redisUtil.zCount("myZSet", 0, 100).orElse(0L);*     System.out.println(count);* </pre>*/public Optional<Long> zCount(String key, double min, double max) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().count(key, min, max)));}/*** 移除有序集合中指定分数范围内的元素* @param key Redis中的key* @param min 最小分数* @param max 最大分数* @return 移除的元素数量* @example* <pre>*     long removed = redisUtil.zRemoveByScore("myZSet", 0, 100).orElse(0L);*     System.out.println(removed);* </pre>*/public Optional<Long> zRemoveByScore(String key, double min, double max) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().removeRangeByScore(key, min, max)));}/*** 移除有序集合中指定排名范围内的元素* @param key Redis中的key* @param start 起始排名* @param end 结束排名* @return 移除的元素数量* @example* <pre>*     long removed = redisUtil.zRemoveByRank("myZSet", 0, 100).orElse(0L);*     System.out.println(removed);* </pre>*/public Optional<Long> zRemoveByRank(String key, long start, long end) {return Optional.ofNullable(execute(() -> redisTemplate.opsForZSet().removeRange(key, start, end)));}private <T> T execute(RedisOperation<T> operation) {try {return operation.execute();} catch (Exception e) {logger.error("Redis operation error", e);return null;}}@FunctionalInterfaceprivate interface RedisOperation<T> {T execute();}
}
2.使用案例
    @RequestMapping("/testRedisUtil")public String testRedisUtil() {// 设置key-valueredisUtil.set("testRedisUtil", "123456");// 获取key对应的value并指定转换的类型String res = redisUtil.get("testRedisUtil", String.class).orElse(null);if (res == null) {return "null";}return res;}

CleanShot 2024-07-20 at 11.08.21@2x


http://www.ppmy.cn/server/152648.html

相关文章

【全栈实战】基于 Vue3 + Wot Design Uni 动手封装组件

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f60a;好久没有更新有关前端实战教程了&#xff0c;本文主要讲解【全栈实战】基于 Vue3 Wot Design Uni 动手封装组件&#xff01; &#x1f60a;这个教程你将会学到技术正确的选型、…

项目搭建+删除(单/批)

一 : 删除没有单独的页面,在列表页面写 二 : 删除在列表的页面 1.删除(单/双)的按钮 ① : 在列表文档就绪函数的ajax里面,成功回调函数追加数据里写删除按钮 注意点 : 删除/修改/回显都是根据id来的,记得传id ② : 批删给批删按钮,定义批删的方法 one : 示例(单删) : //循环追…

POD 存储、PV、PVC

目录 容器如何持久化存储&#xff1f; PV和PVC 为什么不能直接在 Pod 或容器中存储数据&#xff1f; 什么是 PV和 PVC&#xff1f; 可以使用本地磁盘空间创建PV吗&#xff1f; 如何让客户端通过ftp上传到远端服务器的POD里面&#xff1f; 另一个POD想访问ftp的POD里面的…

spring mvc | servlet :serviceImpl无法自动装配 UserMapper

纯注解SSM整合 解决办法&#xff1a; 在MybatisConfig添加 Configuration MapperScan("mapper")

网络安全怎么学习

当我们谈论网络安全时&#xff0c;我们正在讨论的是保护我们的在线空间&#xff0c;这是我们所有人的共享责任。网络安全涉及保护我们的信息&#xff0c;防止被未经授权的人访问、披露、破坏或修改。 一、网络安全的基本概念 网络安全是一种保护&#xff1a;它涉及保护我们的设…

在 Ubuntu 上安装 Muduo 网络库的详细指南

在 Ubuntu 上安装 Muduo 网络库的详细指南 首先一份好的安装教程是非常重要的 C muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装-CSDN博客 像这篇文章就和shit一样&#xff0c;安装到2%一定会卡住&#xff0c;如果你不幸用了这个那真是遭老罪了 环境&#xf…

RK3588 , mpp硬编码yuv, 保存MP4视频文件.

RK3588 , mpp硬编码yuv, 保存MP4视频文件. ⚡️ 传送 ➡️ Ubuntu x64 架构, 交叉编译aarch64 FFmpeg mppRK3588, FFmpeg 拉流 RTSP, mpp 硬解码转RGBRk3588 FFmpeg 拉流 RTSP, 硬解码转RGBRK3588 , mpp硬编码yuv, 保存MP4视频文件.

34 Opencv 自定义角点检测

文章目录 cornerEigenValsAndVecscornerMinEigenVal示例 cornerEigenValsAndVecs void cornerEigenValsAndVecs(InputArray src, --单通道输入8位或浮点图像OutputArray dst, --输出图像&#xff0c;同源图像或CV_32FC(6)int blockSize, --邻域大小值int ape…