README.md

    作者简介

    今年的努力

    我出版的图书

    • 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 - 备注来意

    关于星球

    带你学习,一起成长,专注互联网高并发、高性能、高可用,高可扩展实战型项目和手写中间件项目,以及分享各种硬核技术,从项目中顺带总结各种技术知识点和面试面经。不忘初心,努力成为一个简单、干净而纯粹的技术人,为读者提供有价值的实战型项目和中间件项目以及各种硬核技术。

    加入星球,你将获得:

    1.项目学习:微服务入门必备的SpringCloud Alibaba实战项目、手写RPC项目—所有大厂都需要的项目【含上百个经典面试题】、深度解析Spring6核心技术—只要学习Java就必须深度掌握的框架【含数十个经典思考题】、Seckill秒杀系统项目—进大厂必备高并发、高性能和高可用技能

    2.框架源码:手写RPC项目—所有大厂都需要的项目【含上百个经典面试题】、深度解析Spring6核心技术—只要学习Java就必须深度掌握的框架【含数十个经典思考题】。

    3.硬核技术:深入理解高并发系列(全册)、深入理解JVM系列(全册)、深入浅出Java设计模式(全册)、MySQL核心知识(全册)。

    4.技术小册:深入理解高并发编程(第1版)、深入理解高并发编程(第2版)、从零开始手写RPC框架、SpringCloud Alibaba实战、冰河的渗透实战笔记、MySQL核心知识手册、Spring IOC核心技术、Nginx核心技术、面经手册

    5.技术与就业指导:提供相关就业辅导和未来发展指引,冰河从初级程序员不断沉淀,成长,突破,一路成长为互联网资深技术专家,相信我的经历和经验对你有所帮助。

    冰河的知识星球是一个简单、干净、纯粹交流技术的星球,不吹水,目前领券加入享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星好评的《冰河的渗透实战笔记》电子书。

    项目简介

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

    发行版本

    当前项目没有发行版本

    贡献者 1

    冰 河 @binghe001

    开发语言

    • Java 100.0 %