首页 > 数据库 >redis工具类封装

redis工具类封装

时间:2024-01-14 14:12:37浏览次数:26  
标签:缓存 封装 String redis json key return 工具 id

封装Redis工具类

  • 方法1:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置TTL过期时间

  • 方法2:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置逻辑过期时间,用于处理缓存击穿问题

  • 方法3:根据指定的key查询缓存,并反序列化为指定类型,利用缓存空值的方式解决缓存穿透问题

  • 方法4:根据指定的key查询缓存,并反序列化为指定类型,需要利用逻辑过期解决缓存击穿问题

    @Component
    @Slf4j
     public class CacheClient {
    
        private StringRedisTemplate stringRedisTemplate;
    
        private static final ExecutorService CACHE_REBUILD_EXECUTOR= Executors.newFixedThreadPool(10);
    
    
        public CacheClient(StringRedisTemplate stringRedisTemplate) {
            this.stringRedisTemplate = stringRedisTemplate;
        }
    
        //方法1:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置TTL过期时间
        public void set(String key, Object value,Long time, TimeUnit unit){
            String jsonStr = JSONUtil.toJsonStr(value);
            stringRedisTemplate.opsForValue().set(key,jsonStr,time,unit);
        }
    
        //方法2:将任意Java对象序列化为json并存储在string类型的key中,并且可以设置逻辑过期时间, 用于处理缓存击穿问题
        public void setWithLogicExpire(String key,Object value,Long time,TimeUnit unit){
            //设置逻辑过期
            RedisData redisData = new RedisData();
            redisData.setData(value);
            redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
            //写入Redis
            stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(redisData));
        }
    
        //方法3:根据指定的key查询缓存,并反序列化为指定类型,利用缓存空值的方式解决缓存穿透问题
        public <R,ID> R queryWithPassThrought(String keyPrefix, ID id, Class<R> type, Function<ID,R> dbFallback,Long time,TimeUnit timeUnit) {
            String key= keyPrefix +id;
            //1.从redis查询缓存数据
            String json = stringRedisTemplate.opsForValue().get(key);
            //2.判断缓存数据是否存在
            if (StringUtils.isNotBlank(json)){
                //3.存在,直接返回
                return JSONUtil.toBean(json, type);
            }
            //判断命中的是否为空值
            if (json!=null){
                //返回一个错误信息
                return null;
            }
            //4.不存在,根据id查询
            R r = dbFallback.apply(id);
            //5.不存在,返回错误
            if (r==null){
                //将空值写入Redis
                stringRedisTemplate.opsForValue().set(key,"",RedisConstants.CACHE_NULL_TTL,TimeUnit.MINUTES);
                //返回错误信息
                return null;
            }
            //6.写入redis
            set(key,r,time,timeUnit);
            return r;
        }
    
        //方法4:根据指定的key查询缓存,并反序列化为指定类型,需要利用逻辑过期解决缓存击穿问题
        public <R,ID> R queryWithLogicExpire(String keyPrefix,ID id,Class<R> type,Function<ID,R> dbFallback,Long time,TimeUnit timeUnit){
            String key= keyPrefix +id;
            //1.从redis查
            String json = stringRedisTemplate.opsForValue().get(key);
            //2.判断是否存在
            if (StringUtils.isBlank(json)){
                //不存在,直接返回
                return null;
            }
            //3.命中,把json反序列化为对象
            RedisData redisData = JSONUtil.toBean(json, RedisData.class);
            R r=JSONUtil.toBean((JSONObject) redisData.getData(),type);
            LocalDateTime expireTime = redisData.getExpireTime();
            //4.查看是否过期
            if (expireTime.isAfter(LocalDateTime.now())){
                //未过期,直接返回
                return r;
            }
            //5.已过期,缓存重建
            //6.获取互斥锁
            String lockKey=RedisConstants.LOCK_SHOP_KEY+id;
            boolean isLock = tryLock(lockKey);
            //判断是否获取锁成功
            if (isLock){
                CACHE_REBUILD_EXECUTOR.submit(()->{
                    try {
                        //6.1查询数据库
                        R newR = dbFallback.apply(id);
                        //6.2重建缓存
                        setWithLogicExpire(key,newR,time,timeUnit);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    } finally {
                        //6.3释放锁
                        unlock(key);
                    }
                });
            }
            //7.获取锁失败,返回过期的信息
            return r;
        }
        //方法4:根据指定的key查询缓存,并反序列化为指定类型,需要利用互斥锁解决缓存击穿问题
        public <R, ID> R queryWithMutex(String keyPrefix,ID id,Class<R> type,Function<ID,R> dbFallback,Long time,TimeUnit timeUnit){
            String key=keyPrefix+id;
            //1.从redis查询
            String json = stringRedisTemplate.opsForValue().get(key);
            //2.判断是否存在
            if (StringUtils.isNotBlank(json)){
                //存在直接返回
                return JSONUtil.toBean(json,type);
            }
            //3.判断命中的是否为空值
            if (json!=null){
                //返回一个错误信息
                return null;
            }
            //4.未命中,尝试获取互斥锁
            String lockKey=RedisConstants.LOCK_SHOP_KEY+id;
            R r = null;
            try {
                boolean isLock = tryLock(lockKey);
                // 4.1获取失败,休眠后继续获取
                if (!isLock){
                    Thread.sleep(50);
                    //递归查询
                    return queryWithMutex(keyPrefix, id, type,dbFallback, time, timeUnit);
                }
                //4.2获取成功,查询数据库
                r = dbFallback.apply(id);
                //4.3不存在,返回错误
                if (r==null){
                    //将空值写入redis
                    stringRedisTemplate.opsForValue().set(key,"",time,timeUnit);
                    //返回错误信息
                    return null;
                }
                //4.4存在,写回Redis
                set(key,JSONUtil.toJsonStr(r),time,timeUnit);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                unlock(lockKey);
            }
            //5.返回数据
            return r;
    
        }
    
        private boolean tryLock(String lockKey) {
            Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", RedisConstants.LOCK_SHOP_TTL, TimeUnit.SECONDS);
            return BooleanUtil.isTrue(flag);
        }
    
        private void unlock(String lockKey){
            stringRedisTemplate.delete(lockKey);
        }
    
    }
    

标签:缓存,封装,String,redis,json,key,return,工具,id
From: https://www.cnblogs.com/pdxpdx/p/17963669

相关文章

  • 【JAVA基础】Java项目开发工具之Maven
    JAVA开发工具IDE有哪些?eclipce、idea、vscode等等IDEA比Eclipse更强大和高效。IDEA提供了更好的代码补全和重构功能,更好的代码导航和搜索功能,以及更好的支持多模块项目和多语言开发等。构建项目工具构建项目工具有哪些?Maven、Gradle、Ant等Maven管理和构建项目以及维护......
  • Redis - Why use Redis?
    RedisisfastWhyisRedisfast?AlldataisstoredinmemoryDataisorganizedinsimpledatastructuresRedishasasimplefeatureset       ......
  • 浅谈Linux下傻瓜式磁盘分区工具cfdisk的使用
    对于新手来说,Linux环境下的磁盘分区可能还会存在一些困难。对于熟悉Linux的朋友来说,我们还有fdisk、parted(2TB以上的磁盘分区使用)等磁盘分区工具可以使用。在我们新增磁盘或者在原来磁盘上进行扩容时就会使用到磁盘分区工具,磁盘分区对于整个系统的管理十分重要。1.增加一块容量......
  • 再议Linux中一些发行版中默认下载或上传工具curl的使用
    在目前的CentOS最小化安装发行版中,系统默认的下载/上传工具为:curl。curl支持包括HTTP、HTTPS、ftp等众多协议,还支持POST、cookies、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。我们先来大概看一下curl工具的各选项的大概含义。-a/–append......
  • C#常用工具安装方法及资源整理
    1、GitGit下载地址Git安装教程2、SQLServer2019下载地址安装教程3、VisualStudio2022下载地址安装教程4、TortoiseGit(x64)  2.13.0.1中文版下载地址安装教程5、sqlserver2014下载及安装教程......
  • MD5加密方式(已封装可直接用)
    两个usingusingSystem.Security.Cryptography;usingSystem.Text;一块代码publicstaticstringGenerateMD5(stringtxt){using(MD5mi=MD5.Create()){byte[]buffer=Encoding.Default.GetBytes(txt);......
  • 面向对象之封装
    【一】面向对象三大特性面向对象编程有三大特性:封装、继承、多态其中最重要的一个特性就是封装。封装指的就是把数据与功能都整合到一起【1】什么是封装就是对具体对象的一种抽象简单理解就是把不想让别人看到的对象藏起来【2】为什么要封装有些敏感数据不想......
  • 封装详解
    概念该露的露,该藏的藏我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。封装(数据的隐藏)通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。记住这句话......
  • node版本管理工具推荐
    hello,今天给大家分享几款node版本管理的工具。背景在开发前端项目的时候,特别是新到公司接手一个多年维护的老项目时,如果node版本不正确,有的插件可能无法正确安装,比如我之前提到的node-sass无法安装问题,具体请看:https://www.cnblogs.com/easy1996/p/17945874同时我们在开......
  • redis 数据库
    1redis单机数据库结构1redisserver/client结构 2 每个数据库都有一个包含所有数据的字典 2过期时间redis每个库都会保存一个结构,里面包含了每个键的过期时间的字典结构;redis 如何判断过期,首先检查给的键是否在过期字典中,如果在,那就获取过期时间,在检查当前Un......