SpringBoot Redis入门(一)——redis、Lettuce、Redisson使用

  • 本章:将展示SpringBoot集成Redis三种客户端的配置要点和常见应用示例;
  • 下章:自行实现一个方法级的缓存注解,简化版的Cacheable,使初学者加深对Spring缓存框架的理解。

一、Lettuce客户端

Lettuce 是一种可扩展的、线程安全的 Redis 高级客户端。
从 Spring Boot 2.x 开始, Lettuce 已取代 Jedis 成为SpringBoot 默认的 Redis 客户端。

  • 相比于 Jedis,Lettuce更加全面,并且解决了 Jedis 客户端实例存在非线程安全的问题
  • 支持同步编程,异步编程,响应式编程,自动重新连接,主从模式,集群模块,哨兵模式,管道和编码器等等高级的 Redis 特性
  • Lettuce 底层基于 Netty 框架的事件驱动与 redis 通信,采用了非阻塞的 I/O 操作,可异步调用,相比 Jedis,性能高
  • Lettuce 的 API 是线程安全的,如果不是执行阻塞和事务操作,如 BLPOP 和MULTI/EXEC 等命令,多个线程就可以共享一个连接,性能方面不会衰减。

1.1 pom.xml引入依赖

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> 
    </parent>
    
<dependencies>
        <!-- redis 缓存操作  默认使用 Lettuce 客户端-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- pool 对象池 Lettuce客户端依赖的插件-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <!-- 阿里JSON解析器 -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.34</version>
        </dependency>

        <!-- 方便等会写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

1.2 application.yml

配置redis服务器配置

spring:
    redis:
        # 地址
        host: localhost
        # 端口,默认为6379
        port: 6379
        # 数据库索引
        database: 0
        # 密码
        password: 123456
        # 连接超时时间
        timeout: 10s
        lettuce:
            pool:
                # 连接池中的最小空闲连接
                min-idle: 0
                # 连接池中的最大空闲连接
                max-idle: 8
                # 连接池的最大数据库连接数
                max-active: 8
                # #连接池最大阻塞等待时间(使用负值表示没有限制)
                max-wait: -1ms

1.3 redis缓存应用

UserService.java

@Service
public class UserService {

	//由于引入redis-starter包,spring已经完成了RedisTemplate 对象创建,什么都不用做就可以直接使用了。
    @Autowired
    RedisTemplate redisTemplate;

	/**
     * 最简单的使用,通过key-value方式存取变量;
     * @param username
     * @return
     */
    public Object getUserInfo(String username) {
    	//通过用户名从缓存获取用户信息,如果没有即新建并存缓存起来;
        if (redisTemplate.opsForValue().get(username) == null) {
            System.out.println("未获取到缓存,新建用户信息.............");
            Map<String, Object> user = new HashMap<>();
            user.put("username", username);
            user.put("usercode", "zhangsan");
            user.put("sex", "男");
            user.put("createtime", new Date());
            redisTemplate.opsForValue().set(username, user);
        }
        return redisTemplate.opsForValue().get(username);
    }

	//从缓存获取,如果没有则新建,并设置了过期时间为10秒。
    public Object getUserInfo2(String username) {
        if (redisTemplate.opsForValue().get(username) == null) {
            System.out.println("未获取到缓存,新建用户信息.............");
            Map<String, Object> user = new HashMap<>();
            user.put("username", username);
            user.put("usercode", "zhangsan");
            user.put("sex", "男");
            user.put("createtime", DateUtils.format(new Date()));
            redisTemplate.opsForValue().set(username, user);
            //10秒后过期
            redisTemplate.expire(username, 10, TimeUnit.SECONDS);
        }
        return redisTemplate.opsForValue().get(username);
    }
}

1.3测试

UserServiceTest.java

    @Test
    public void testRedis() {
        Object user = userService.getUserInfo("2");
        System.out.println(user);
    }

输出:

在这里插入图片描述

给缓存设置过期时间,再来存取。

@Test
    public void testRedisExpire() throws InterruptedException {
        System.out.println(userService.getUserInfo2("11"));
        Thread.sleep(1000);
        System.out.println(userService.getUserInfo2("11"));
        Thread.sleep(1000);
        System.out.println(userService.getUserInfo2("11"));
        Thread.sleep(9000);
        System.out.println(userService.getUserInfo2("11"));
    }

输出:
缓存过期时间设置为10秒,当第4次取值时,发现已经过期,自然需要新建对象了。
在这里插入图片描述

二、Redis客户端

Jedis 是一款老牌 Redis 的 Java 客户端,提供了比较全面的 Redis 命令的操作支持,也是目前使用最广泛的客户端。
优点如下:

  • Jedis 的 API 提供了比较全面的 Redis 命令的支持
  • Jedis 中的 Java 方法基本和 Redis 的 API 保持着一致,也就是说了解 Redis 的API,可以熟练的使用 Jedis
  • 支持 pipelining、事务、LUA Scripting、Redis Sentinel、Redis Cluster等等 redis 提供的高级特性
  • 客户端轻量,简洁,便于集成和改造

缺点如下:

  • 使用阻塞的 I/O 操作,且其方法调用都是同步的,程序流需要等到 sockets 处理完 I/O 才能执行,不支持异步
  • Jedis 在实现上是直接连接的 redis server,如果在多线程环境下是非线程安全的,这个时候可以使用连接池来管理 Jedis,已解决 Jedis 客户端实例存在非线程安全的问题
  • 不支持读写分离,需要自己实现

2.1 pom.xml依赖引入

在实际SpringBoot项目中绝大多数情况都不会要求说使用Redis客户端,只有遇到变态需求时可能才会用到吧。不论是用Lettuce 还是用Redis,SpringBoot提供给我们使用的RedisTemplate 接口都是一致的。和Lettuce的差异只是引入的包的差异,SpringBoot已经默认帮我们引入Letucce了,如果要用Redis,那还得排除Letucce的引入,而指定引入Redis。如下:

 <!-- 实现对 Spring Data Redis 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <!-- 去掉对 Lettuce 的依赖,因为 Spring Boot 优先使用 Lettuce 作为 Redis 客户端 -->
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 引入 Jedis 的依赖,这样 Spring Boot 实现对 Jedis 的自动化配置 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

代码中使用方法与Lettuce是完成一致的。

三、Redisson

Redisson 是一个在 Redis 的功能基础上实现的 Java 驻内存数据网格客户端。实现了分布式和可扩展的 Java 数据结构,提供很多分布式相关操作服务,例如分布式锁,分布式集合,可通过 Redis 支持延迟队列

Redisson和前两兄弟的区别就像一个用鼠标操作图形化界面,一个用命令行操作文件。Redisson是更高层的抽象,Jedis和Lettuce是Redis命令的封装。

Reddisson 的出现不是又来干一次Redis和Lettuce干过的事儿,而是站在巨人肩膀上干更大的事儿:让猿猿们在分布式场景下也能少掉些头发
优点如下:

  • 实现了分布式特性和可扩展的 Java 数据结构,例如分布式锁,分布式集合,分布式对象,分布式远程调度等等高级功能,适合分布式开发
  • 与 Lettuce 一样,基于 Netty 框架的事件驱动与 redis 通信,支持异步调用,性能高
  • Redisson 的 API 是线程安全的,所以可以使用单个 Redisson 连接来完成各种操作。
  • 支持读写分离,支持读负载均衡,在主从复制和 Redis Cluster 架构下都可以使用
  • 内建 Tomcat Session Manager,为 Tomcat 6/7/8 提供了会话共享功能,可以与 Spring Session 集成,实现基于 Redis 的会话共享
  • 相比于 Jedis、Lettuce 等基于 redis 命令封装的客户端,Redisson 提供的功能更加高端和抽象,Redisson 可以类比 Spring 框架,这些框架搭建了应用程序的基础框架和功能,可以显著提升开发效率,让开发者有更多的时间来关注业务逻辑

所以从应用上讲,Redis和Lettuce能做的是Redisson都能做,其次还能干分布式下的粗活累活。

3.1 依赖引入

Redisson本身是基于Redis做的延伸,所以引入Redisson的时候就已经引入Redis包了,所以只需引入Redisson依赖就可以使用Redis的相关功能了。只是使用上与前面会有差异,效果都一样。

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter </artifactId>

        </dependency>
        <!--使用redisson作为缓存-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.17.3</version>
        </dependency>

3.2Redisson对象配置

由于没有引入SpringBoot对Redisson的自动配置,这里进行手动配置一下,创建RedissonConfiguration.java

package com.luo.chengrui.labs.lab03.config;

import org.redisson.Redisson;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * redis配置
 */
@Configuration
public class RedissonConfig extends CachingConfigurerSupport {

	//创建redisson对象,这是单机版,另外还支持哨兵,和集群。
    @Bean(name = "redisson")
    @ConditionalOnProperty(prefix = "spring.redis", name = "host")
    public Redisson redissonSingleServer(@Value("${spring.redis.host}") String host, @Value("${spring.redis.port}") String port, @Value("${spring.redis.password}") String password) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + host + ":" + port);
        config.useSingleServer().setPassword(password);
        return (Redisson) Redisson.create(config);
    }

}

3.3 redis服务器配置

与前面的配置一毛一样。。。。

3.4 Redisson的应用:(一)作为缓存


@Service
public class UserService {

    @Autowired
    Redisson redisson;
    @Resource
    private RedissonClient redissonClient;

    private static final String USER_CACHE = "USER_CACHE";

	//与Redis、Lettuce相似的功能,这里使用MapCache,还提供了如对列、链表等对象
    public Object getUser(String username) {
        if (redissonClient.getMapCache(USER_CACHE).get(username) == null) {
            System.out.println("未获取到缓存,新建用户信息.............");
            Map<String, Object> user = new HashMap<>();
            user.put("username", username);
            user.put("usercode", "zhangsan");
            user.put("sex", "男");
            user.put("createtime", new Date());
            redissonClient.getMapCache(USER_CACHE).put(username, user);
        }
        return redissonClient.getMapCache(USER_CACHE).get(username);
    }
 }

代码验证:

 @Test
    public void mapCache() {
        System.out.println(userService.getUser("11"));
        System.out.println(userService.getUser("2"));
    }

输出:
在这里插入图片描述
Redis服务器端存储数据展示,这里由于没有配置序列化,所以键和值都编码过了,不太识别。
在这里插入图片描述

3.5 Redisson应用:(二)分布式锁

测试代码为两个方法:处理用户消息打印。一个加了分布式锁,一个没有加锁的方法,测试时使用多线程模拟分布式效果。

  • 加了分布式锁,即希望所有服务端同一时间仅一人能说话,其他人必须 等待说了“完毕”后,才能说话;
  • 不加分布式锁,不加分布式锁,但同一时间仅一人能说话,实际也应该加锁。但对于分布式来说,单机加不加锁都不影响。为了测试就不加锁。

不用分布式锁:

    public void print(String user, String content) {
        try {

            System.out.println(String.format("收到%s的消息", user));
            System.out.println(String.format("%s说:%s", user, content));
            Thread.sleep(3000);
            System.out.println(String.format("%s说完了", user));
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {

        }
    }
    @Test
    public void print() {
        new Thread(() -> {
            userService.print("张三", "你好");
        }).start();
        new Thread(() -> {
            userService.print("李四", "你好");
        }).start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

输出:
都没有等张三说“完毕”时,李四已经开始说话了。如果是在做秒杀、抢购。那只能快点提桶跑路!
在这里插入图片描述

加了分布式锁的情况:

public void printLock(String user, String content) {
        RLock lock = null;
        try {
            lock = redisson.getLock("printNow");
            lock.lock();
            System.out.println(String.format("收到%s的消息", user));
            System.out.println(String.format("%s说:%s", user, content));
             for (int i = 0; i < 3; i++) {
                System.out.println("思考中....");
                Thread.sleep(1000);
            }
            System.out.println("完毕....");
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }
    }
 @Test
    public void printLock() {
        new Thread(() -> {
            userService.printLock("张三", "你好");
        }).start();
        new Thread(() -> {
            userService.printLock("李四", "你好");
        }).start();

        try {
            Thread.sleep(50000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

输出:加了分布式锁之后,只要没有说完毕,张三就必须一直等待。
在这里插入图片描述

综上,本章内容完毕了。

总结

  • Lettuce是SpringBoot自带的Redis客户端,性能比Redis要好, 是线程安全的,支持同步编程,异步编程,响应式编程,自动重新连接,主从模式,集群模块,哨兵模式
  • Redisson 是一个在 Redis 的功能基础上实现的 Java 驻内存数据网格客户端。实现了分布式和可扩展的 Java 数据结构,提供很多分布式相关操作服务,例如分布式锁,分布式集合,可通过 Redis 支持延迟队列。

1、Lettuce的自动配置

	<!-- redis 缓存操作自动配置  使用 Lettuce 客户端-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- pool 对象池 Lettuce 要依赖这个-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

代码中使用自动注入即可

@Service
public class UserService {
    @Autowired
    RedisTemplate redisTemplate;
    //redisTemplate.opsForValue().get("zhangsan")
    //redisTemplate.opsForValue().set("zhangsan", "李四");
}

2、Redisson的自动配置

引入redisson的自动配置后,我们上面示例中的RedissonConfiguration类也不需要写了,直接用就行。

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.17.3</version>
        </dependency>

代码中直接注入即可:

@Service
public class UserService {

    @Autowired
    Redisson redisson;
    @Resource
    private RedissonClient redissonClient;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/294454.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

lf 的年终总结(2023)

这一年&#xff0c; 我没有进行总结&#xff0c; 只有年终的回顾。 是的&#xff0c; 我又长了一岁&#xff0c; 同时也度过了三年的开发经历&#xff0c; 即将进入五年 Android 开发的阶段。 我只希望在新的一年里能够好好学习&#xff0c;期待有所提升。 回顾过去的生活&…

FAST-LIO2:论文和算法解析

文章目录 摘要一、简介二、相关工作2.1雷达惯导里程计2.2 建图过程中的动态数据结构 三、系统架构四、状态估计A. 卡尔曼模型1.状态转换模型2.测量模型 B.迭代卡尔曼滤波1. 预测过程2. 残差计算3.迭代更新 五、建图A.地图管理B.树的结构与创建1.数据结构2.ikd树的创建 C.地图的…

给Flutter + FireBase 增加 badge 徽章,App启动器 通知红点。

在此之前需要配置好 firebase 在flutter 在项目中。&#xff08;已经配置好的可以忽略此提示&#xff09; Firebase 配置教程&#xff1a;flutter firebase 云消息通知教程 (android-安卓、ios-苹果)_flutter firebase_messaging ios环境配置-CSDN博客 由于firebase 提供的消息…

ThreadLocal 是什么?它的实现原理呢?

一个工作了 4 年的小伙伴&#xff0c;又私信了我一个并发编程里面的问题。 他说他要抓狂了&#xff0c;每天 CRUD&#xff0c;也没用到过 ThreadLocal 啊&#xff0c;怎么就不能问我怎么写CRUD 呢&#xff1f; 我反问他如果只问你项目和业务&#xff0c;那有些 4 年的小伙伴他…

光线追踪原理

理论 参考 实现光线追踪算法 光线追踪算法采用由像素组成的图像。对于图片中的每个像素&#xff0c;它会将主光线射入场景&#xff08;从眼睛&#xff08;或相机&#xff09;射入场景的第一条光线称为主光线、能见度光线或相机光线。&#xff09;。该主光线的方向是通过追踪…

2.0.0 BGP高级特性-ASFilter、CommunityFilter、ORF、对等组

Peer Group BGP对等体组 在网络中出现多台设备配置相近的情况下&#xff0c;使用对等体组可以极大的减少配置命令的输入。 与端口组类似&#xff0c;通过创建一个组&#xff0c;然后将成员添加入其中&#xff0c;可以对组中的成员进行统一的管理。 案例配置1 以AR2为例&…

Python split()方法详解:分割字符串

Python 中&#xff0c;除了可以使用一些内建函数获取字符串的相关信息外&#xff08;例如 len() 函数获取字符串长度&#xff09;&#xff0c;字符串类型本身也拥有一些方法供我们使用。 注意&#xff0c;这里所说的方法&#xff0c;指的是字符串类型 str 本身所提供的&#x…

ubuntu22.04配置双网卡绑定提升带宽

这里写自定义目录标题 Bonding简介配置验证参考链接 Bonding简介 bonding(绑定)是一种linux系统下的网卡绑定技术&#xff0c;可以把服务器上n个物理网卡在系统内部抽象(绑定)成一个逻辑上的网卡&#xff0c;能够提升网络吞吐量、实现网络冗余、负载均衡等功能&#xff0c;有很…

专业课130+,总分390+四川大学951信号与系统考研通信,电子信息经验分享

今年专业课130&#xff0c;总分390&#xff0c;顺利上岸&#xff0c;将近一年复习一路走来&#xff0c;感慨很多&#xff0c;希望以下经历可以给后来的同学提供一些参考。 初试备考经验 公共课&#xff1a;三门公共课&#xff0c;政治&#xff0c;英语&#xff0c;数学。在备…

基于SSM+Jsp的叮当书城、网上书城购物系统(有文档Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

怎么用活码二维码生成器?多种活码在线制作

扫码看内容的方式被很多行业应用&#xff0c;最常见的内容就是展现文字、图片、视频等类型&#xff0c;那么这种将不同内容组合展示的方法是什么样的呢&#xff1f;想要制作二维码最简单的方法可以使用二维码生成器工具来处理&#xff0c;下面就将具体的二维码制作的步骤分享给…

如何使用可视化管理工具DockerUI远程管理docker容器

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

数据资产入表正式施行,企业如何对数据资产进行会计核算?

2024年1月1日&#xff0c;《企业数据资源相关会计处理暂行规定》正式施行&#xff0c;数据资源将作为资产在企业的会计和财务报告中确认、计量、报告和披露。这代表着企业数据相关的支出由损益变成资产类&#xff0c;可以计入资产&#xff0c;不仅可以减少投入期对利润的影响&a…

浅谈园区建设“一站式企业服务平台”的必要性!

​ 随着数字经济的快速发展与新一代信息技术的日新月异&#xff0c;打造智慧型、高效能的园区运营模式已成为现代产业园区转型升级的关键路径&#xff0c;其中&#xff0c;构建“一站式企业服务平台”成为了园区创新企业服务机制、提升企业服务效能、优化营商环境的重要举措。 …

IP地址定位技术的应用及其重要性

随着网络技术的快速发展&#xff0c;网络安全问题日益凸显&#xff0c;IP地址定位技术在网络安全领域的应用也越来越广泛。本文将介绍IP地址定位技术在网络安全领域的应用及其重要性。 一、IP地址定位技术概述 IP地址定位技术是指通过一定的技术手段&#xff0c;将虚拟网络中的…

液冷数据中心生态建设启动:浪潮信息力推绿色算力产业发展

近日&#xff0c;由中国电子技术标准化研究院主办的“节能环保低碳 我们在行动”第二届电子信息行业绿色环保大会在江苏无锡盛大举行。会上&#xff0c;中国电子技术标准化研究院、浪潮信息等五家发起单位共同启动“液冷数据中心生态建设”&#xff0c;浪潮信息服务器产品线总经…

电子招标采购系统源码之从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理

随着市场竞争的加剧和企业规模的扩大&#xff0c;招采管理逐渐成为企业核心竞争力的重要组成部分。为了提高招采工作的效率和质量&#xff0c;我们提出了一种基于电子化平台的解决方案。该方案旨在通过电子化招投标&#xff0c;使得招标采购的质量更高、速度更快&#xff0c;同…

cissp 第10章 : 物理安全要求

10.1 站点与设施设计的安全原则 物理控制是安全防护的第一条防线&#xff0c;而人员是最后一道防线。 10.1.1 安全设施计划 安全设施计划通过关键路径分析完成。 关键路径分析用于找出关键应用、流程、运营以及所有必要支撑元索间的关系。 技术融合指的是各种技术、解决方案…

gRPC接口怎样从proto文件到具体使用

proto文件转为头文件和源码 proto文件是一种预编译的规定文件&#xff0c;用来告诉gRPC 的服务如何生成对应的代码。 具体的使用方式请参考&#xff1a;介绍文档&#xff1a;proto 文件的关键字介绍 具体的说&#xff0c;一个proto文件分为三部分&#xff1a;指定环境&#…

SpringIOC之ApplicationListenerDetector

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌ 博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…