Skip to content

📚 基于Redis解决缓存击穿、穿透和雪崩问题的通用解决方案,拿来即用。支持存储对象、集合、简单数据类型等。无需提前将数据存入Redis,直接使用提供的分布式缓存接口查询数据即可,附带完善的单元测试用例,方便学习使用。

License

Notifications You must be signed in to change notification settings

binghe001/spring-redis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

作者简介

今年的努力 ✨

我出版的图书

  • 2020年出版《海量数据处理与大数据技术实战》 —— 涵盖企业级大数据处理方方面面的知识,并从零搭建并开发离线批处理系统和在线实时计算系统。
  • 2020年出版《MySQL技术大全:开发、优化与运维实战》 —— 程序员与运维工程师必备的700多页的MySQL工具书,涵盖MySQL基础、开发、优化、运维和架构方方面面的知识。
  • 2021年出版《深入理解分布式事务:原理与实战》 —— 全网首部系统、深入讲解分布式事务的书籍,涵盖:分布式事务基础、解决方案、原理、源码与实战等篇章,真正从企业实际需求出发,系统、深入的讲解分布式事务,来自京东、阿里、腾讯、蚂蚁金服、滴滴、饿了么、58集团、IBM等互联网大厂及Apache软件基金会的近20位专家高口碑力荐。
  • 2022年出版《深入理解高并发编程:核心原理与案例实战》 —— 全面、系统、深入的讲解高并发技术,涵盖:并发基础、原理、实战与架构的方方面面知识。来自阿里巴巴、蚂蚁金服、京东、高德、CSDN、饿了么、58集团等互联网大厂以及多家互联网独角兽企业的近20位专家高口碑力荐。
  • 2022年出版《深入高平行開發:深度原理&專案實戰》 —— 《深入理解高并发编程:核心原理与案例实战》的繁体版书籍。
  • 2023年出版《深入理解高并发编程:JDK核心技术》 ——全面、系统、深入的讲解JDK高并发编程技术,涵盖:JDK并发基础、核心工具和线程池核心技术等篇章,深度剖析了JDK中各种并发类库和线程池的核心源码,并提供手写线程池案例。来自阿里巴巴、腾讯、蚂蚁金服、京东、高德、CSDN、饿了么、58集团等互联网大厂以及多家互联网独角兽企业的近20位专家高口碑力荐。

我的部分电子书

  • 《深入理解高并发编程(第2版)》 —— 全书共计 八 大篇章,433页,耗时 4 个月完成,全网最全的高并发编程知识手册,涵盖:学习路线、源码分析、JDK核心类库、基础案例、实战案例、性能优化、面试、和系统架构等篇章,发布当月下载量即突破5万,全网累计下载30万+。
  • 《深入理解高并发编程(第1版)》 —— 全书共计 五 大篇章节,392页,耗时6个月完成。涵盖源码分析、基础案例、实战案例、面试和系统架构等篇章,全网累计下载65万+。
  • SpringCloud Alibaba实战 》—— 全书共计 十 大篇章,26个章节,332页,涵盖:专栏设计、微服务介绍、微服务环境搭建、服务治理、服务容错、服务网关、链路追踪、消息服务、服务配置和分布式事务等篇章,全网累计下载10万+。
  • 冰河的渗透实战笔记 》 —— 冰河整理的全网首个开源的以实战案例为背景的渗透实战笔记,全书共442页,共计37万字(不计空格)。整本书的内容涵盖:Kali基础、渗透工具、木马制作、钓鱼链接生成、爆破密码、内存溢出攻击、web渗透、数据提权、社会工程学,全网累计下载20万+。
  • 从零开始写RPC框架(基础版) 》 —— 在RPC框架中会实现同步调用、异步调用、回调调用、单向调用和泛化调用。框架中会使用大量的SPI技术来实现扩展性,其中,整个框架会采用微内核、插件化的开发模式,最终真正做一款可在实际场景使用的RPC框架。
  • 《MySQL核心技术》 —— 全书共19章、16万字,涵盖了MySQL核心基础知识的方方面面内容,非常适合MySQL数据库初学者入门,也适合MySQL技术高手系统化的梳理MySQL基础知识,及时查漏补缺,全网累计下载5万+。
  • 《Spring IOC核心技术》 —— 全书共27章,19万字,涵盖Spring IOC最核心的技术,全网累计下载8万+。

联系我

添加微信:hacker_binghe - 备注来意

一、介绍:星球介绍

冰河技术知识星球是冰河创建的付费编程学习、交流社群,我相信每个程序员的硬盘或者云盘里存放着几百GB甚至几TB的编程资料和学习视频,但多又怎么样?出现问题你能问谁?又能去哪里咨询问题呢?冰河的知识星球则不同,在星球里冰河会对你的问题进行 1v1 解答,为你指定学习路线、学习方案和规划职业生涯路线。最终的目标就是有针对性的帮助每一位加入星球的小伙伴,通过学习星球的硬核技术和项目,提升业务理解能力、系统架构能力,充分掌握大厂真正落地的核心技术、架构思维、编程思想、代码技巧,不只是为了面试,更多的是为自己的职业生涯保驾护航。

如果你一直在小公司做CRUD,一直忙碌于外包项目,正在迷茫,找不到除了CRUD以外更具深度的项目,不知道学什么,从哪里学,该怎么学,怎么让自己更具竞争力,怎么更好的提升自己,怎么将自己的能力充分体现在简历上,怎么在面试短短的几十分钟内充分展现自己的水平。冰河技术知识星球会给你答案,冰河会在这里为你铺好路,让你一往直前。

知识星球支持安卓IOSPC网页端和小程序,可以随时打开学习,在你每天上下班坐公交和地铁时,或者在带薪如厕时,都可以随时打开知识星球学习,也许某次的学习就能让你在面试、述职、升职加薪、晋升答辩时脱颖而出!

星球APP&小程序截图:


星球PC网页端截图:


各位小伙伴们可以下载知识星球APP,加入冰河技术知识星球体验一下。

二、为啥:加入星球?

加入星球,你可以获得已经在编程这条路上踩坑多年的互联网资深技术专家,为你提供的服务。


1.学习技术&项目

很多小伙伴困于自己在小厂、外包或者刚毕业和未毕业,手里根本就没有什么拿的出手的项目,也没有什么好的阅历,导致投向大厂的简历石沉大海。

加入星球可以直接学习到冰河在大厂多年沉淀下来的核心技术,带你编写超出大厂预期的实战项目,包括但不限于:并发编程、性能调优、框架源码、分布式、微服务、领域驱动设计、互联网工程、Seckill分布式秒杀系统、分布式IM系统、分布式高性能RPC框架、高性能网关等。

1.1 业务场景项目

1.2 中间件项目

1.3 硬核项目

  • 手写Redis-源码已完成
  • 手写JVM-源码已完成
  • 手写APM-源码已完成

1.4 源码解析

1.5 技术小册

1.6 招聘面试

2.答疑解惑

其实很多技术和知识并不难,而是你不知道,也没有人告诉你,如果你自己去探索、去研究,可能要花费数月甚至数年才能搞懂。而这样的技术、知识和项目在冰河的知识星球,每天都在产出。你可以在星球向冰河提问题项目架构设计、面试面经问题、晋升答辩细节,也可以参见冰河回答其他小伙伴的疑问,这些内容都能够帮你少走弯路,在最短的时间内提升自己的综合素质和硬核技能。


注:限于篇幅,上图只接触了少部分回答,大部分回答内容和学习建议没截出来,大家可自行到星球查看。

这只是星球其中一个问题的回答,有时,小伙伴一句话的提问,可能要写几百上千字来回答,在星球提问基本就赚了!

冰河会在星球中回答大量这样的问题,有时小伙伴备注私聊的问题,我会选择单独发给小伙伴们,在星球的每一个菜单栏下,都对应着相关的知识内容、专栏文档、技术小册、视频课程、技术资料等等,坚决不割韭菜,让每一个加入星球的小伙伴都感觉值得。

3.关于简历

冰河在星球除了帮助小伙伴们优化、改进简历外,还为大家提供了1000+套星球专属精美简历模板与面试技巧。

部分简历模板如下所示。


部分面试技巧如下所示。


  • 经过一年多的积累,星球的内容远远不止这些,无论是星球内容、课程资料、学习方法等都已经建设的比较全面了,后续会更加完善和全面。
  • 星球里有很多来自211/985名校的新人,也有工作几年的小伙伴,他们更懂得如何用最短时间,更快找到学习干货的最佳途经。

三、加入:知识星球

星球价格 ¥299 一年,新用户领券(关注冰河技术公众号,回复星球领券。或者点击 加入星球 扫码加入)加入,老用户续费5折一年(星球会不断开发新的技术专栏、硬核项目、技术小册等内容)。

加入星球后,如果不满意,3天内可以全额退款,感兴趣的小伙伴可以先加入体验,判断对自己是否有价值。


注意: 加入星球后,阅读星球置顶消息 https://t.zsxq.com/14EatpDHH 申请项目代码权限。

同时,按照《中华人民共和国著作权法实施条例》未经原作者允许和书面授权,禁止以任何理由和目的,分享星球项目到其他任何github、gitee等平台,违反可追究进一步的法律行动。

四、星球:值得学吗?

星球值不值得学,来看看加入星球的小伙伴怎么说吧。




跟着冰河学,你只管努力提升自己的技能和水平,有问题及时向冰河提问,进大厂是迟早的事儿。

五、关于:星球定价

1.星球内的专栏和硬核实战项目都是冰河本人原创,加入星球可以学习星球内的所有技术和项目,每个项目的实际价值都远超门票,会带着大家从零开始架构设计,手写硬核项目,搭配有专栏文档,笔记、源码工程,遇到问题可以提,碰到Bug可以修复,这肯定比单独买一个课程或者一套源码要划算的多。星球门票其实远不及培训班、补习班一节课的钱,并且他们的课程可能还没有冰河讲的透彻,让你听的明白。

2.冰河每天会投入大量精力在星球的创作上,包括分享技术、架构设计、项目开发、答疑解惑、优化简历、就业与晋升指导等。这些内容会占据冰河大量的时间和精力,需要每天晚上9点~12点,周末和假期不断维护。所以,冰河的星球会随着项目的递增和加入的人数涨价(本次涨价¥20),否则,真的有点维护不过来了。也真心希望加入星球的小伙伴给自己一个交代,下定决心,一起进步。

3.如果在星球的努力真的让你实现了跳槽大厂、升职加薪的目标,再回过头来看,你会觉得这是一笔对自己最有价值的投资。

4.最后,星球会随着项目的递增和加入的人数涨价,感谢大家的理解!但是,已经加入星球的小伙伴,每次续费的折扣都是很大的,只相当于付了星球新增技术、专栏和项目的费用。对比下来,这个价格就相当便宜了。

🧧点此领优惠券加入星球

冰河的知识星球是一个简单、干净、纯粹交流技术的星球,不吹水,目前领券加入享5折优惠,价值远超门票。加入星球的用户,记得添加冰河微信:hacker_binghe,冰河拉你进星球专属VIP交流群。


关于本仓库

📚 基于Redis解决缓存击穿、穿透和雪崩问题的通用解决方案,拿来即用。支持存储对象、集合、简单数据类型等。无需提前将数据存入Redis,直接使用提供的分布式缓存接口查询数据即可,附带完善的单元测试用例,方便学习使用。

分布式缓存核心接口源码详见:io.binghe.redis.cache.distribute.DistributeCacheService
默认基于Redis的实现类的源码详见:io.binghe.redis.cache.distribute.redis.RedisDistributeCacheService
也可以基于SpringBoot的@ConditionalOnProperty注解扩展基于其他缓存中间件的实现类
项目配有完善的单元测试用例,具体测试源码详见:src/test/java目录下的io.binghe.redis.test.DistributeCacheServiceTest

核心接口定义

分布式缓存核心接口源码详见:io.binghe.redis.cache.distribute.DistributeCacheService

/**
 * @author binghe(微信 : hacker_binghe)
 * @version 1.0.0
 * @description 分布式缓存接口,通用型接口,在满足分布式缓存的需求时,解决了缓存击穿、穿透和雪崩的问题
 * @github https://github.com/binghe001
 * @copyright 公众号: 冰河技术
 */
public interface DistributeCacheService {

    /**
     * 永久缓存
     * @param key 缓存key
     * @param value 缓存value
     */
    void set(String key, Object value);

    /**
     * 将数据缓存一段时间
     * @param key 缓存key
     * @param value 缓存value
     * @param timeout 物理缓存的时长
     * @param unit 物理时间单位
     */
    void set(String key, Object value, Long timeout, TimeUnit unit);

    /**
     * 保存缓存时设置逻辑过期时间
     * @param key 缓存key
     * @param value 缓存value
     * @param timeout 缓存逻辑过期时长
     * @param unit 缓存逻辑时间单位
     */
    void setWithLogicalExpire(String key, Object value, Long timeout, TimeUnit unit);

    /**
     * 获取缓存中的数据
     * @param key 缓存key
     * @return 缓存value
     */
    String get(String key);

    /**
     * 带参数查询对象和简单类型数据,防止缓存穿透
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存的业务标识,
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     * @param <ID> 查询数据库参数泛型,也是参数泛型类型
     */
    <R,ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询对象和简单类型数据,防止缓存穿透
     * @param keyPrefix key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> R queryWithPassThroughWithoutArgs(String keyPrefix, Class<R> type, Supplier<R> dbFallback, Long timeout, TimeUnit unit);
    /**
     * 带参数查询集合数据,防止缓存穿透
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存的业务标识,
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     * @param <ID> 查询数据库参数泛型,也是参数泛型类型
     */
    <R,ID> List<R> queryWithPassThroughList(String keyPrefix, ID id, Class<R> type, Function<ID, List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询集合数据,防止缓存穿透
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> List<R> queryWithPassThroughListWithoutArgs(String keyPrefix, Class<R> type, Supplier<List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 带参数查询数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存逻辑过期时长
     * @param unit 缓存逻辑过期时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> R queryWithLogicalExpire(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> R queryWithLogicalExpireWithoutArgs(String keyPrefix, Class<R> type, Supplier<R> dbFallback, Long timeout, TimeUnit unit);
    /**
     * 带参数查询集合数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存逻辑过期时长
     * @param unit 缓存逻辑过期时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> List<R> queryWithLogicalExpireList(String keyPrefix, ID id, Class<R> type, Function<ID, List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询集合数据,按照逻辑过期时间读取缓存数据,新开线程重建缓存,其他线程直接返回逻辑过期数据,不占用资源
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存的时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> List<R> queryWithLogicalExpireListWithoutArgs(String keyPrefix, Class<R> type, Supplier<List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> R queryWithMutex(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> R queryWithMutexWithoutArgs(String keyPrefix, Class<R> type, Supplier<R> dbFallback, Long timeout, TimeUnit unit);
    /**
     * 带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param id 缓存业务标识,也是查询数据库的参数
     * @param type 缓存的实际对象类型
     * @param dbFallback 查询数据库的Function函数
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 业务数据
     * @param <R> 结果数据泛型类型
     * @param <ID> 查询数据库泛型类型,也是参数泛型类型
     */
    <R, ID> List<R> queryWithMutexList(String keyPrefix, ID id, Class<R> type, Function<ID, List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 不带参数查询数据,按照互斥锁方式获取缓存数据,同一时刻只有一个线程访问数据库,其他线程访问不到数据重试
     * @param keyPrefix 缓存key的前缀
     * @param type 缓存的实际对象类型
     * @param dbFallback 无参数查询数据库数据
     * @param timeout 缓存时长
     * @param unit 时间单位
     * @return 返回业务数据
     * @param <R> 结果泛型
     */
    <R> List<R> queryWithMutexListWithoutArgs(String keyPrefix, Class<R> type, Supplier<List<R>> dbFallback, Long timeout, TimeUnit unit);

    /**
     * 将对象类型的json字符串转换成泛型类型
     * @param obj 未知类型对象
     * @param type 泛型Class类型
     * @return 泛型对象
     * @param <R> 泛型
     */
    default <R> R getResult(Object obj, Class<R> type){
        if (obj == null){
            return null;
        }
        //简单类型
        if (TypeConversion.isSimpleType(obj)){
            return Convert.convert(type, obj);
        }
        return JSONUtil.toBean(JSONUtil.toJsonStr(obj), type);
    }

    /**
     * 将对象类型的json字符串转换成泛型类型的List集合
     * @param str json字符串
     * @param type 泛型Class类型
     * @return 泛型List集合
     * @param <R> 泛型
     */
    default <R> List<R> getResultList(String str, Class<R> type){
        if (StrUtil.isEmpty(str)){
            return null;
        }
        return JSONUtil.toList(JSONUtil.parseArray(str), type);
    }

    /**
     * 获取简单的key
     * @param key key
     * @return 返回key
     */
    default String getKey(String key){
        return getKey(key, null);
    }

    /**
     * 不确定参数类型的情况下,使用MD5计算参数的拼接到Redis中的唯一Key
     * @param keyPrefix 缓存key的前缀
     * @param id 泛型参数
     * @return 拼接好的缓存key
     * @param <ID> 参数泛型类型
     */
    default <ID> String getKey(String keyPrefix, ID id){
        if (id == null){
            return keyPrefix;
        }
        String key = "";
        //简单数据类型与简单字符串
        if (TypeConversion.isSimpleType(id)){
            key = StrUtil.toString(id);
        }else {
            key = MD5.create().digestHex(JSONUtil.toJsonStr(id));
        }
        if (StrUtil.isEmpty(key)){
            key = "";
        }
        return keyPrefix.concat(key);
    }

    /**
     * 获取要保存到缓存中的value字符串,可能是简单类型,也可能是对象类型,也可能是集合数组等
     * @param value 要保存的value值
     * @return 处理好的字符串
     */
    default String getValue(Object value){
        return TypeConversion.isSimpleType(value) ? String.valueOf(value) : JSONUtil.toJsonStr(value);
    }
}

使用案例(测试用例)

1.User类模拟从数据库查询对象类型的数据
源码详见:io.binghe.redis.test.bean.User

public class User {

    private Long id;
    private String name;

    public User() {
    }

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return JSONUtil.toJsonStr(this);
    }
}

2.DistributeCacheServiceTest类测试各种场景
源码详见:io.binghe.redis.test.DistributeCacheServiceTest

@SpringBootTest
@RunWith(SpringRunner.class)
public class DistributeCacheServiceTest {

    @Autowired
    private DistributeCacheService distributeCacheService;


    @Test
    public void testQueryWithPassThrough(){
        User user = distributeCacheService.queryWithPassThrough("pass:through:", 1002852L, User.class,  this::getUser, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(user));
    }
    @Test
    public void testQueryWithPassThroughWithoutArgs(){
        User user = distributeCacheService.queryWithPassThroughWithoutArgs("pass:through001:", User.class,  this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(user));
    }

    @Test
    public void testQuerySimpleDataWithPassThrough(){
        Integer id = distributeCacheService.queryWithPassThrough("pass:through2:", 100285210, Integer.class,  this::getId, 60L, TimeUnit.SECONDS);
        System.out.println(id);
    }
    @Test
    public void testQuerySimpleDataWithPassThroughWithoutArgs(){
        Integer id = distributeCacheService.queryWithPassThroughWithoutArgs("pass:through2002:",  Integer.class,  this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(id);
    }

    @Test
    public void testQueryWithPassThroughList(){
        List<User> list = distributeCacheService.queryWithPassThroughList("pass:through:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }
    @Test
    public void testQueryWithPassThroughListWithoutArgs(){
        List<User> list = distributeCacheService.queryWithPassThroughListWithoutArgs("pass:through:list003:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }

    @Test
    public void testQuerySimpleDataWithPassThroughList(){
        List<Integer> list = distributeCacheService.queryWithPassThroughList("pass:through:list2:", 100285211, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }
    @Test
    public void testQuerySimpleDataWithPassThroughListWithoutArgs(){
        List<Integer> list = distributeCacheService.queryWithPassThroughListWithoutArgs("pass:through:list2004:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }

    @Test
    public void testQueryWithLogicalExpire(){
        User user = distributeCacheService.queryWithLogicalExpire("logical:expire:", 1002852L, User.class,  this::getUser, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(user));
    }

    @Test
    public void testQueryWithLogicalExpireWithoutArgs(){
        User user = distributeCacheService.queryWithLogicalExpireWithoutArgs("logical:expire005:", User.class,  this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(user));
    }

    @Test
    public void testQuerySimpleDataWithLogicalExpire(){
        Integer id = distributeCacheService.queryWithLogicalExpire("logical:expire2:", 100285212, Integer.class,  this::getId, 60L, TimeUnit.SECONDS);
        System.out.println(id);
    }
    @Test
    public void testQuerySimpleDataWithLogicalExpireWithoutArgs(){
        Integer id = distributeCacheService.queryWithLogicalExpireWithoutArgs("logical:expire2006:", Integer.class,  this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(id);
    }

    @Test
    public void testQueryWithLogicalExpireList(){
        List<User> list = distributeCacheService.queryWithLogicalExpireList("logical:expire:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }
    @Test
    public void testQueryWithLogicalExpireListWithoutArgs(){
        List<User> list = distributeCacheService.queryWithLogicalExpireListWithoutArgs("logical:expire:list007:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }

    @Test
    public void testQuerySimpleDataWithLogicalExpireList(){
        List<Integer> list = distributeCacheService.queryWithLogicalExpireList("logical:expire:list2:", 100285213, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }
    @Test
    public void testQuerySimpleDataWithLogicalExpireListWithoutArgs(){
        List<Integer> list = distributeCacheService.queryWithLogicalExpireListWithoutArgs("logical:expire:list2008:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }

    @Test
    public void testQueryWithMutex(){
        User user = distributeCacheService.queryWithMutex("mutex:", 1002852L, User.class,  this::getUser, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(user));
    }
    @Test
    public void testQueryWithMutexWithoutArgs(){
        User user = distributeCacheService.queryWithMutexWithoutArgs("mutex009:", User.class,  this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(user));
    }

    @Test
    public void testQuerySimpleDataWithMutex(){
        Integer id = distributeCacheService.queryWithMutex("mutex2:", 100285214, Integer.class,  this::getId, 60L, TimeUnit.SECONDS);
        System.out.println(id);
    }
    @Test
    public void testQuerySimpleDataWithMutexWithoutArgs(){
        Integer id = distributeCacheService.queryWithMutexWithoutArgs("mutex2010:", Integer.class,  this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(id);
    }

    @Test
    public void testQueryWithMutexList(){
        List<User> list = distributeCacheService.queryWithMutexList("mutex:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }
    @Test
    public void testQueryWithMutexListWithoutArgs(){
        List<User> list = distributeCacheService.queryWithMutexListWithoutArgs("mutex:list011:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }

    @Test
    public void testQuerySimpleDataWithMutexList(){
        List<Integer> list = distributeCacheService.queryWithMutexList("mutex:list2:", 123, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }

    @Test
    public void testQuerySimpleDataWithMutexListWithoutArgs(){
        List<Integer> list = distributeCacheService.queryWithMutexListWithoutArgs("mutex:list2012:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
        System.out.println(JSONUtil.toJsonStr(list));
    }

    /**
     * 模拟带参数从数据库查询对象
     */
    public User getUser(Long id){
        return new User(id, "binghe");
    }

    /**
     * 默认不带参数从数据库查询对象
     */
    public User getUserWithoutArgs(){
        return new User(1L, "binghe");
    }

    /**
     * 模拟带参数查询从数据库对象列表
     */
    public List<User> getUserList(String type){
        return Arrays.asList(
                new User(1L, "binghe001"),
                new User(2L, "binghe002"),
                new User(3L, "binghe003")
        );
    }

    /**
     * 模拟不带参数从数据库查询对象列表
     */
    public List<User> getUserListWithoutArgs(){
        return Arrays.asList(
                new User(1L, "binghe001"),
                new User(2L, "binghe002"),
                new User(3L, "binghe003")
        );
    }

    /**
     * 模拟带参数从数据库查询简单数据类型数据
     */
    public Integer getId(Integer id){
        return id;
    }

    /**
     * 模拟不带参数从数据库查询简单数据类型数据
     */
    public Integer getIdWithoutArgs(){
        return 0;
    }

    /**
     * 模拟带参数从数据库查询简单数据类型数据列表
     */
    public List<Integer> getIds(Integer id){
        return Arrays.asList(0,0,0);
    }

    /**
     * 模拟不带参数从数据库查询简单数据类型数据列表
     */
    public List<Integer> getIdsWithoutArgs(){
        return Arrays.asList(0,0,0);
    }
}

加群交流

本群的宗旨是给大家提供一个良好的技术学习交流平台,所以杜绝一切广告!由于微信群人满 100 之后无法加入,请扫描下方二维码先添加作者 “冰河” 微信(hacker_binghe),备注:学习加群

冰河微信

公众号

分享各种编程语言、开发技术、分布式与微服务架构、分布式数据库、分布式事务、云原生、大数据与云计算技术和渗透技术。另外,还会分享各种面试题和面试技巧。内容在 冰河技术 微信公众号首发,强烈建议大家关注。

公众号:冰河技术

视频号

定期分享各种编程语言、开发技术、分布式与微服务架构、分布式数据库、分布式事务、云原生、大数据与云计算技术和渗透技术。另外,还会分享各种面试题和面试技巧。

视频号:冰河技术

星球

加入星球 冰河技术,可以获得本站点所有学习内容的指导与帮助。如果你遇到不能独立解决的问题,也可以添加冰河的微信:hacker_binghe, 我们一起沟通交流。另外,在星球中不只能学到实用的硬核技术,还能学习实战项目

关注 冰河技术公众号,回复 星球 可以获取入场优惠券。

知识星球:冰河技术

冰河整理PDF

关注 冰河技术 微信公众号:

回复 “并发编程2” 领取《深入理解高并发编程(第2版)》PDF电子书。

回复 “并发编程” 领取《深入理解高并发编程(第1版)》PDF电子书。

回复 “并发源码” 领取《并发编程核心知识(源码分析篇 第1版)》PDF电子书。

回复 “并发路线” 领取并发编程高清学习路线。

回复 “SA实战” 领取《SpringCloud Alibaba实战》PDF电子书。

回复 “渗透笔记” 领取《冰河的渗透实战笔记》PDF电子书。

回复 “ngx2” 获取《Nginx核心技术手册》PDF电子书。

回复 “我要进大厂” 领取《我要进大厂系列之面试圣经(第1版)》PDF电子书。

回复 ”限流“ 领取《亿级流量下的分布式解决方案》PDF电子书。

回复 “设计模式” 领取《深入浅出Java23种设计模式》PDF电子书。

回复 “Java8新特性” 领取 《Java8新特性教程》PDF电子书。

回复 “分布式存储” 领取《跟冰河学习分布式存储技术》 PDF电子书。

回复 “Nginx” 领取《跟冰河学习Nginx技术》PDF电子书。

回复 “互联网工程” 领取《跟冰河学习互联网工程技术》PDF电子书。

回复 “冰河索引” 领取《冰河技术公号文章索引》PDF电子书。

回复 “星球” 获取知识星球优惠券 。

公众号文章同步(善用 Ctrl+F 搜索文章)

我的新书

书籍介绍

星球专栏

💥 Seckill秒杀系统(星球热更中...)

🔥🔥🔥 RPC手撸专栏

RPC框架介绍

第一篇:整体设计

第二篇:服务提供者

第三篇:服务消费者

第四篇:注册中心

第五篇:负载均衡

第六篇:SPI扩展序列化机制

第七篇:SPI扩展动态代理机制

第八篇:SPI扩展反射机制

第九篇:SPI扩展负载均衡策略

第十篇:SPI扩展增强型负载均衡策略

第十一篇:SPI扩展实现注册中心

第十二篇:心跳机制

第十三篇:增强型心跳机制

第十四篇:重试机制

第十五篇:整合Spring

第十六篇:整合SpringBoot

第十七篇:整合Docker

第十八篇:整合SpringCloud Alibaba

第十九篇:结果缓存

第二十篇:路由控制

第二十一篇:延迟连接

第二十二篇:并发控制

第二十三篇:流控分析

第二十四篇:连接控制

第二十五篇:SPI扩展连接淘汰策略

第二十六篇:数据缓冲

第二十七篇:服务容错(降级)

第二十八篇:服务限流

第二十九篇:基于SPI扩展限流策略

第三十篇:超出限流规则

第三十一篇:服务熔断

第三十二篇:基于SPI扩展熔断策略

第三十三篇:异常监控

维护篇:持续维护篇

番外篇

🔥🔥🔥 Spring核心技术

专栏介绍

第一篇:IOC容器

第二篇:AOP切面

第三篇:声明式事务

第四篇:AOT预编译

第五篇:SpringMVC

作业篇

🔥🔥🔥 精通高并发系列

手撸源码系列

🔥🔥🔥 SA实战

第一篇:专栏设计

第二篇:微服务介绍

第三篇:微服务环境搭建

第四篇:服务治理

第五篇:服务容错

第六篇:服务网关

第七篇:链路追踪

第八篇:消息服务

第九篇:服务配置

第十篇:分布式事务

结束语

整合bhrpc框架

🔥🔥🔥 MySQL核心知识

字节码编程

面试必问系列

架构师进阶系列

分布式事务系列

精通JVM系列

视频号系列

性能调优系列

一起进大厂系列

互联网工程

精通渗透系列

精通大数据系列

精通运维系列

吃透MySQL系列

Mycat系列

Oracle专题

程序员进阶系列

Java8新特性

云原生专题

开源框架与中间件系列

分布式缓存系列

分布式存储

微服务专题

Nginx技术

Spring注解系列

设计模式系列

Kafka系列

算法专题

Dubbo系列

MyBatis源码系列

网路编程

深度思考

程序人生

视频系列

小工具

Python专题

重磅福利

微信搜一搜【冰河技术】微信公众号,关注这个有深度的程序员,每天阅读超硬核技术干货,公众号内回复【PDF】有我准备的一线大厂面试资料和我原创的超硬核PDF技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作,学习是一条时而郁郁寡欢,时而开怀大笑的路,加油。如果你通过努力成功进入到了心仪的公司,一定不要懈怠放松,职场成长和新技术学习一样,不进则退。如果有幸我们江湖再见!

另外,我开源的各个PDF,后续我都会持续更新和维护,感谢大家长期以来对冰河的支持!!

回复【并发编程2】获取冰河最新整理的《深入理解高并发编程(第2版)》电子书。
回复【并发编程】获取全网累计下载60W+的《深入理解高并发编程》电子书。
回复【渗透笔记】获取全网5星好评的《冰河的渗透实战笔记》电子书。

About

📚 基于Redis解决缓存击穿、穿透和雪崩问题的通用解决方案,拿来即用。支持存储对象、集合、简单数据类型等。无需提前将数据存入Redis,直接使用提供的分布式缓存接口查询数据即可,附带完善的单元测试用例,方便学习使用。

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages