玩转SpringBoot之捣鼓 Redis

我们都知道,把首页数据放到Redis里,能够加快首页数据的访问速度。但是我们要如何准确又快速的将 Redis 整合到自己的 SpringBoot2.x 项目中呢?今天阿淼就带大家爬一爬其中的门门道道。

序、Redis 介绍

Redis 使用了浪费流量的文本协议,但因为它数据存储在内存中的,相对而言,依然可以取得极高的访问性能。并且 Redis 是线程安全的。

RESP 就是 Redis 序列化协议的简称。它是一种直观的文本协议,优势在于实现异常简单,解析性能极好。

Redis 协议里面虽然有大量冗余的回车换行符,但是这不影响它成为技术领域非常受欢迎的一个文本协议。在技术领域,性能并不总是一切,还有简单性、易理解性和易实现性,这些都需要进行适当权衡。

一、Redis 基础数据结构

1、字符串:(缓存)

  • key:value

value 可以是对象转换成的 JSON 字符串,也可以是对象序列化后的二进制字符串

2、列表:(异步队列)
类似linkedlist

  • 右边进左边出:队列
  • 右边进右边出:栈

3、字典(哈希)
类似hashmap:数组+链表

不过rehash是渐进式hash策略

4、集合:(去重)

  • 无序 set: 类似hashset
  • 有序 zset:类似SortedSet和HashMap的结合体,内部是现实现是跳跃列表

二、Lettuce

随着 Spring Boot2.x 的到来,支持的组件越来越丰富,也越来越成熟,其中对 Redis 的支持不仅仅是丰富了它的API,更是替换掉底层 Jedis 的依赖,取而代之换成了 Lettuce。

虽然 Lettuce 和 Jedis 的都是连接 Redis Server 的客户端程序,但是 Jedis 在实现上是直连 redis server,多线程环境下非线程安全,除非使用连接池,为每个Jedis实例增加物理连接。而 Lettuce 基于 Netty 的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满足多线程环境下的并发访问,同时它是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。

Lettuce是可扩展的Redis客户端,用于构建无阻塞的Reactive应用程序.

Luttuce官网:https://lettuce.io/

玩转SpringBoot之捣鼓 Redis

谷歌翻译后的页面是:

玩转SpringBoot之捣鼓 Redis

原来这玩意儿叫生菜,你别说,看着图标还真有点像。

玩转SpringBoot之捣鼓 Redis

三、实操

项目中使用的 SpringBoot2.x 实现,如果之前是 SpringBoot1.x 则需要注意,底层已经由 Jedis 升级成了 Lettuce 。

3.1、引入依赖

除去 SpringBoot 项目需要的 jar 包外,另外还需要引入 redis 相关的依赖:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-data-redis</artifactid>
</dependency>
<dependency>
    <groupid>org.apache.commons</groupid>
    <artifactid>commons-pool2</artifactid>
</dependency>

3.2、 application.yml 配置文件

此处用到的 application.yml 文件,配置如下:

spring:
  redis:
    # Redis&#x9ED8;&#x8BA4;&#x60C5;&#x51B5;&#x4E0B;&#x6709;16&#x4E2A;&#x5206;&#x7247;&#xFF0C;&#x8FD9;&#x91CC;&#x914D;&#x7F6E;&#x5177;&#x4F53;&#x4F7F;&#x7528;&#x7684;&#x5206;&#x7247;&#x3002;&#x9ED8;&#x8BA4;&#x662F;&#x7D22;&#x5F15;&#x4E3A;0&#x7684;&#x5206;&#x7247;
    database: 1
    # Redis&#x670D;&#x52A1;&#x5668;&#x5730;&#x5740;
    host: 127.0.0.1
    # Redis&#x670D;&#x52A1;&#x5668;&#x8FDE;&#x63A5;&#x7AEF;&#x53E3;
    port: 6379
    # Redis&#x670D;&#x52A1;&#x5668;&#x8FDE;&#x63A5;&#x5BC6;&#x7801;&#xFF08;&#x9ED8;&#x8BA4;&#x4E3A;&#x7A7A;&#xFF09;
    password: mmzsblog
    # &#x8FDE;&#x63A5;&#x8D85;&#x65F6;&#x65F6;&#x95F4;&#xFF08;&#x6BEB;&#x79D2;&#xFF09;
    timeout: 2000s

    # &#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x4E2D;&#x6DFB;&#x52A0; lettuce.pool &#x76F8;&#x5173;&#x914D;&#x7F6E;&#xFF0C;&#x5219;&#x4F1A;&#x4F7F;&#x7528;&#x5230;lettuce&#x8FDE;&#x63A5;&#x6C60;
    lettuce:
      pool:
        # &#x8FDE;&#x63A5;&#x6C60;&#x6700;&#x5927;&#x963B;&#x585E;&#x7B49;&#x5F85;&#x65F6;&#x95F4;&#xFF08;&#x4F7F;&#x7528;&#x8D1F;&#x503C;&#x8868;&#x793A;&#x6CA1;&#x6709;&#x9650;&#x5236;&#xFF09; &#x9ED8;&#x8BA4; -1
        max-wait: 60s
        # &#x8FDE;&#x63A5;&#x6C60;&#x4E2D;&#x7684;&#x6700;&#x5927;&#x7A7A;&#x95F2;&#x8FDE;&#x63A5; &#x9ED8;&#x8BA4; 8
        max-idle: 10
        # &#x8FDE;&#x63A5;&#x6C60;&#x4E2D;&#x7684;&#x6700;&#x5C0F;&#x7A7A;&#x95F2;&#x8FDE;&#x63A5; &#x9ED8;&#x8BA4; 0
        min-idle: 10
        # &#x8FDE;&#x63A5;&#x6C60;&#x6700;&#x5927;&#x8FDE;&#x63A5;&#x6570;&#xFF08;&#x4F7F;&#x7528;&#x8D1F;&#x503C;&#x8868;&#x793A;&#x6CA1;&#x6709;&#x9650;&#x5236;&#xFF09; &#x9ED8;&#x8BA4; 8
        max-activ: 8

如果项目是由 SpringBoot1.x 升级到 SpringBoot2.x 的,要沿用 jedis 连接池配置时会用到配置 jedis 相关的属性:

    # 配置文件中添加 jedis.pool 相关配置,则会使用到 jedis 连接池
    jedis:
      pool:
        max-active: 10
        max-idle: 8
        min-idle: 0
        max-wait: 60s

并且引用的 jar 包也需要调整:


    org.springframework.boot
    spring-boot-starter-data-redis

            io.lettuce
            lettuce-core

    redis.clients
    jedis

另外,这里再贴一下 Spring Boot 关于 RedisProperties 的所有配置项

REDIS RedisProperties
spring.redis.cluster.max-redirects= # Maximum number of redirects to follow when executing commands across the cluster.

spring.redis.cluster.nodes= # Comma-separated list of "host:port" pairs to bootstrap from.

spring.redis.database=0 # Database index used by the connection factory.

spring.redis.url= # Connection URL. Overrides host, port, and password. User is ignored. Example: redis://user:password@example.com:6379
spring.redis.host=localhost # Redis server host.

spring.redis.jedis.pool.max-active=8 # Maximum number of connections that can be allocated by the pool at a given time. Use a negative value for no limit.

spring.redis.jedis.pool.max-idle=8 # Maximum number of "idle" connections in the pool. Use a negative value to indicate an unlimited number of idle connections.

spring.redis.jedis.pool.max-wait=-1ms # Maximum amount of time a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely.

spring.redis.jedis.pool.min-idle=0 # Target for the minimum number of idle connections to maintain in the pool. This setting only has an effect if it is positive.

spring.redis.lettuce.pool.max-active=8 # Maximum number of connections that can be allocated by the pool at a given time. Use a negative value for no limit.

spring.redis.lettuce.pool.max-idle=8 # Maximum number of "idle" connections in the pool. Use a negative value to indicate an unlimited number of idle connections.

spring.redis.lettuce.pool.max-wait=-1ms # Maximum amount of time a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely.

spring.redis.lettuce.pool.min-idle=0 # Target for the minimum number of idle connections to maintain in the pool. This setting only has an effect if it is positive.

spring.redis.lettuce.shutdown-timeout=100ms # Shutdown timeout.

spring.redis.password= # Login password of the redis server.

spring.redis.port=6379 # Redis server port.

spring.redis.sentinel.master= # Name of the Redis server.

spring.redis.sentinel.nodes= # Comma-separated list of "host:port" pairs.

spring.redis.ssl=false # Whether to enable SSL support.

spring.redis.timeout= # Connection timeout.

3.3、自定义一个 RedisTemplate

这个看你自己,不自定义也不影响使用,只是说可能不那么顺手,所以阿淼习惯自定义一个。因为 Spring BootRedisAutoConfiguration 中默认配置了 RedisTemplate<object, object></object,>StringRedisTemplate两个模板类,然而 RedisTemplate<object, object></object,>并未指定 keyvalue的序列化器。

@Configuration
public class RestTemplateConfig {
    @Bean
    public RedisTemplate redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

3.4、 Person 实体类

声明一个 Person 实体类:

/**
 * @author :created by mmzsblog
 * @date :created at 2020/06/23 16:41
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Serializable {

    private static final long serialVersionUID = -8183942491930372236L;
    private Long userId;
    private String username;
    private String password;
}

3.5、测试

通过编写一个 UserController 来进行测试:

@RestController
public class UserController {
    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/set")
    public String set() {
        stringRedisTemplate.opsForValue().set("one", "1");

        // redisTemplate 保存的是字节序列,因为 RestTemplateConfig 自定义的时候指定了 key 和 value 的序列化器。
        redisTemplate.opsForValue().set("two", "2");
        redisTemplate.opsForValue().set("person", new Person(1L, "luffy", "123456789"));

        // 测试线程安全
        ExecutorService executorService = Executors.newFixedThreadPool(1000);
        IntStream.range(0, 1000).forEach(i -> {
            executorService.execute(() -> stringRedisTemplate.opsForValue().increment("num", 1));
        });
        return "Ok!";
    }

    @GetMapping("/get")
    public String get() {
        String one = stringRedisTemplate.opsForValue().get("one");
        if ("1".equals(one)) {
            System.out.println("key: one" + " || value: " + one);
        }

        Object two = redisTemplate.opsForValue().get("two");
        if ("2".equals(two.toString())) {
            System.out.println("key: two" + " || value: " + two);
        }

        Person user = (Person) redisTemplate.opsForValue().get("person");
        if ("luffy".equals(user.getUsername())) {
            System.out.println("key: person" + " || value: " + user);
        }
        return "Ok!";
    }
}

用RedisDesktopManager工具查看,数据如下:

StringRedisTemplate 设置的键值是String类型的:

玩转SpringBoot之捣鼓 Redis

RedisTemplate 设置的键值是二进制的字节流形式存储的,从截图中的 [Binary] 标识符也能看出:

玩转SpringBoot之捣鼓 Redis

自定义的 RedisTemplateStringRedisTemplate 并不会有什么冲突,想用 String 存储还是二进制的字节流形式存储完全取决于你自己。

代码地址:https://www.mmzsblog.cn/articles/2020/06/24/1592963113998.html

参考

Original: https://www.cnblogs.com/mmzs/p/13185912.html
Author: 淼淼之森
Title: 玩转SpringBoot之捣鼓 Redis

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/529034/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 模拟重装Kubernetes(k8s)集群:删除k8s集群然后重装

    服务器版本 docker软件版本 CPU架构 CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 x86_64…

    Linux 2023年6月7日
    080
  • Docker学习笔记

    镜像下载、域名解析、时间同步请点击阿里云开源镜像站 Docker概述 Docker学习链接 官网链接:Home – Docker Docker与虚拟机比较 虚拟化技术 …

    Linux 2023年5月27日
    084
  • 记一次从源码泄露到getshell(二)

    0x00 前言 文章所述漏洞已经提交至漏洞平台,且所有恶意操作均已复原 0x01 源码泄露 http://www.xxx.com.cn/www.zip 老规矩拿到源码先通关关键词找…

    Linux 2023年5月28日
    0101
  • 从零开始制作一个linux iso镜像

    一、前言 对于一个极简化的linux系统而言,只需要三个部分就能组成,它们分别是一个linux内核、一个根文件系统和引导。以下是本文制作linux iso镜像所用到的系统和软件: …

    Linux 2023年5月27日
    077
  • WPF 已知问题 Popup 吃掉 PreviewMouseDown 事件

    在 WPF 中,使用 Popup 也许会看到 PreviewMouseDown 事件被吃掉 因为 PreviewMouseDown 是 RoutingStrategy.Direct…

    Linux 2023年6月6日
    0119
  • MYSQL快速安装整理

    【检查是否已安装过】 find / -name mysql 【快速安装开始】 groupadd mysql ;useradd -g mysql mysql;cd /usr/loca…

    Linux 2023年6月6日
    063
  • JavaScript快速入门-06-函数

    6 函数 6.1 函数定义 函数可以封装语句,然后在任何地方、任何时间执行。JavaScript中的函数使用 function关键字声明,主要由 函数名、 函数参数和 函数体组成。…

    Linux 2023年6月7日
    093
  • MySQL之多表查询、Navicat及pymysql

    一、多表查询 1.1 数据准备 — 建表 create table dep( id int primary key auto_increment, name varchar(20…

    Linux 2023年6月14日
    099
  • Docker容器搭建android编译环境

    Docker容器搭建android编译环境 .版本:v0.4作者:河东西望日期:2022-7-12. 1.1 手动部署 &#x5B89;&#x88C5;&#…

    Linux 2023年6月7日
    091
  • Scrapy关键词 爬虫的简单实现(以新华网和人民网为例)

    新华网爬虫(2022年6月) 1 分析网站结构 新华网网址:新华网_让新闻离你更近 (news.cn) 新华网的首页是带有关键词搜索功能的,我们尝试在搜索栏随意搜索一个关键词 可以…

    Linux 2023年6月7日
    0103
  • 蓝桥杯真题:纯质数

    蓝桥杯 2021 年国赛真题《纯质数》的 Python 解法。 蓝桥杯 2021 年国赛真题:纯质数。 题目大意 输出 1 到 20210605 之间(包括两端)的”纯…

    Linux 2023年6月13日
    096
  • CAP 5.1 版本发布通告 你期待的 Redis 来了

    前言 今天,我们很高兴宣布 CAP 发布 5.1 版本正式版,在这个版本里我们同样引入了更多令人激动的新特性和改进,同时也得到越来越多人的喜爱。 得益于社区的反馈和贡献者的支持,在…

    Linux 2023年5月28日
    097
  • 消息中间件MQ的学习境界和路线

    在《深入理解Java类加载机制,再也不用死记硬背了》里我提到了对于一门语言的”会”的三个层次。本篇将以知识地图的形式展现学习消息中间件MQ各个层次要掌握的内…

    Linux 2023年6月14日
    0100
  • Windows关闭135/137/139/445 端口

    通过IP安全策略(以关闭135端口为例) (1) 依次打开”控制面板–>系统和安全–>管理工具–>本地安全策略&#…

    Linux 2023年6月8日
    0215
  • Mysql数据库体系

    Mysql数据库体系如下(手绘): 描述: 1.DBMS:database system management是数据库管理软件,平时我们使用的数据库的全称,是C/S架构(clien…

    Linux 2023年6月14日
    091
  • 机器学习学习笔记之一:K最近邻算法(KNN)

    假定数据有M个特征,则这些数据相当于在M维空间内的点 [X = \begin{pmatrix} x_{11} & x_{12} & … & x_…

    Linux 2023年6月14日
    068
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球