专栏首页用户5521492的专栏SpringBoot 实战 (二十)| 整合 Redis

SpringBoot 实战 (二十)| 整合 Redis

前言

两个月没更新原创了,实在惭愧。没有借口,就是因为自己懒了。最近看了「刻意学习」,这本书谈的是学习与行动的关系,书中提到了「持续行动」 这个概念,意思就是:我们要去实实在在地去做一些事情,而且是每天都做,才能称之为「持续行动」。看完这本书以后,我意识到我必须要做些什么,那就是写作。

Redis 简介

Redis 是一个开源的,基于内存的键值数据存储,用作数据库,缓存和消息代理。在实现方面,Key-Value 存储代表 NoSQL 空间中最大和最老的成员之一。Redis 支持数据结构,如字符串,散列,列表,集和带范围查询的有序集。 在 spring data redis 的框架,可以很容易地编写,通过提供一个抽象的数据存储使用 Redis 的键值存储的 Spring 应用程序。 非关系型数据库,基于内存,存取数据的速度不是关系型数据库所能比拟的 redis 是键值对 (key-value) 的数据库

数据类型

1. 字符串类型 string

2. 散列类型 hash

3. 列表类型 list

4. 集合类型 set

5. 有序集合类型 zset

其中,因为SpringBoot 约定大于配置的特点,只要我们加入了 spring-data-redis 依赖包并配置 Redis 数据库,SpringBoot 就会帮我们自动配置一个 RedisTemplate ,利用它我们就可以按照以下方式操作对应的数据类型,在下面实战中我将会对这五种数据进行操作。

1. redisTemplate.opsForValue(); //操作字符串

2. redisTemplate.opsForHash(); //操作hash

3. redisTemplate.opsForList(); //操作list

4. redisTemplate.opsForSet(); //操作set

5. redisTemplate.opsForZSet(); //操作有序set

开发环境

1. SpringBoot 2.1.6 RELEASE

2. Spring-data-redis 2.1.9 RELEASE

3. Redis 3.2

4. IDEA

5. JDK8

6. mysql

关于如何安装 Redis 这里不再赘述,请自行搜索引擎搜索解决。

pom 依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

配置文件

spring:

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456

  jpa:
    hibernate:
      ddl-auto: update   #ddl-auto:设为 create 表示每次都重新建表
    show-sql: true

  redis:
    host: localhost
    port: 6379
    # Redis数据库索引(默认为0)
    database: 1
    jedis:
      pool:
        #连接池最大连接数
        max-active: 8
        #最小空闲连接
        min-idle: 0
        #最大阻塞等待时间,负值表示没有限制
        max-wait: -1ms
        #最大空闲连接
        max-idle: 8
    #连接超时时间(毫秒)
    timeout: 20ms
    # 无密码可不写
    # password:

为什么乱码?

    /**
     * 添加字符串
     */
    @Test
    public void setString(){
        redisTemplate.opsForValue().set(USERKEY,"nasus");
        redisTemplate.opsForValue().set(AGEKEY,24);
        redisTemplate.opsForValue().set(CITYKEY,"清远");
    }

首先是添加字符串类型的数据。它的运行结果如下:

添加字符串

如何解决乱码

我们可以看到插入的数据是乱码的,这是因为 SpringBoot 自动配置的这个 RedisTemplate 是没有设置数据读取时的 key 及 value 的序列化方式的。所以,我们要写一个自己的 RedisTemplate 并设置 key 及 value 的序列化方式才可以正常操作 Redis。如下:

@Configuration
public class RedisConfig {

    private final RedisTemplate redisTemplate;

    @Autowired
    public RedisConfig(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Bean
    @SuppressWarnings("unchecked")
    public RedisTemplate<String, Object> redisTemplate() {
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        //RedisSerializer<Object> jsonString = new GenericToStringSerializer<>(Object.class);
        RedisSerializer<Object> jsonString = new FastJsonRedisSerializer<>(Object.class);
        // String 的 key 和 hash 的 key 都采用 String 的序列化方式
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        // value 都采用 fastjson 的序列化方式
        redisTemplate.setValueSerializer(jsonString);
        redisTemplate.setHashValueSerializer(jsonString);
        return redisTemplate;
    }

}

这时,再次运行上面的单元测试,结果就正常了。

正常序列化结果

操作 List

    /**
     * 添加、获取LIST
     */
    @Test
    public void setList(){
        List<Student> students = studentService.findStudentList();
        log.info("students size = {}", students.size());
        //循环向 studentList 左添加值
        students.forEach(value->redisTemplate.opsForList().leftPush(LISTKEY,value));
        //向 studentList 右添加值
        Student student = new Student();
        student.setId(10);
        student.setAge(24);
        student.setName("rightPush");
        redisTemplate.opsForList().rightPush(LISTKEY,student);
        // 获取值
        log.info("studentList->{}",redisTemplate.opsForList().range(LISTKEY,0,10));
    }

这里需要说一下,leftpush 和 rightpush 的区别,前者是在 key 对应 list 的头部添加元素,也就是我们常说的后来居上,List下标最大的元素在这个 list 里面处于第一位;而后者则是 在 key 对应 list 的尾部添加元素,刚好和前者相反。

获取值,代码这里获取的是 0 到 10 行的数据,控制台打印结果:

[{"name":"优秀","id":9,"age":22}, {"name":"冯某华","id":8,"age":25}, {"name":"蓝某城","id":7,"age":25}, {"name":"优秀","id":6,"age":22}, {"name":"冯某华","id":5,"age":25}, {"name":"蓝某城","id":4,"age":25}, {"name":"冯某华","id":3,"age":25}, {"name":"蓝某城","id":2,"age":25}, {"name":"废人","id":1,"age":22}, {"name":"rightPush","id":10,"age":24}]

添加 List 结果:

添加 List

这里注意 1 到 9 行的 id 值刚好是相反的,而正常情况下,我从 mysql 数据中查出来的值是这样的:

mysql 查询结果

因此,验证了 leftpush 和 rightpush 的区别。

操作 set

    /**
     * 添加和获取Set
     */
    @Test
    public void setAndGetSet(){
        List<String> usernameList = new ArrayList<>();
        usernameList.add("nasus");
        usernameList.add("nasus");
        usernameList.add("一个优秀的废人");
        //循环向添加值
        usernameList.forEach(value->redisTemplate.opsForSet().add(SETKEY,value));
        log.info("取出usernameSet->{}",redisTemplate.opsForSet().members(SETKEY));
    }

    /**
     * 删除 Set
     */
    @Test
    public void delSet(){
        redisTemplate.opsForSet().remove(SETKEY,"nasus");
    }

Redis 的 set 数据结构跟 java 的 hashset 数据结构一样,也是无序且不重复。所以我代码里 add 了两个 nasus 字符串,其实只 add 了一个 nasus 。结果如下:

添加 set

操作 hash

分别作了 hash 的添加、删除以及获取,代码如下:这里需要说明一下的是,hash 的 hash 有两个键可以设置,其中第一个是 redis 中的键,而第二个是具体每条数据的 hashkey。

    /**
     * 添加 hash
     */
    @Test
    public void setHash(){
        List<Student> students = studentService.findStudentList();
        //添加
        for (Student student : students){
            redisTemplate.opsForHash().put(HASHKEY, student.getId().toString(), student);
        }
    }

    /**
     * 删除 hash
     */
    @Test
    public void delHash(){
        Student student = studentService.findStudentById(0);
        // 删除
        redisTemplate.opsForHash().delete(HASHKEY,JSON.toJSONString(student));
    }

    /**
     * 获取 Hash
     */
    @Test
    public void getHash(){
        List<Student> students = redisTemplate.opsForHash().values(HASHKEY);
        log.info("values = {}", students);
    }

添加 hash 操作结果:

添加 hash

获取 hash 操作结果:

获取 hash

源码地址

https://github.com/turoDog/Demo/tree/master/springboot_redis_demo

本文分享自微信公众号 - 一个优秀的废人(feiren_java),作者:nasus

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java 基础 | Collection 集合概览

    老读者都知道,我是自学转行到 java 的。那时迫于生存压力,学得比较快,很多知识点仅停留在会用的层面。最近,光会用不知道原理,没什么意思。每次使用时都是机械性...

    一个优秀的废人
  • Java | 如何做好异常处理?

    这周身体不适请了两天病假,只上了三天班。本来不打算发文,但写文章这件事我很想做好。咬咬牙还是坚持下去。废话少说,今天给你们带来的是如何做好 Java 中的异常处...

    一个优秀的废人
  • 聊聊工作中常用的设计模式

    来 源:cnblogs.com/ILoke-Yang/p/8054466.html

    一个优秀的废人
  • spring boot2.0.0 redis序列化解决方案

    24-丰总
  • 设计模式一:简单工厂模式

    简单工厂模式属于创建型模式,又叫做静态工厂方法(Static Factory Method)。简单工厂模式是由一个工厂对象决定创建哪一种产品类实例。在简单工厂模...

    对弈
  • 小程序订阅消息推送(含源码)java实现小程序推送,springboot实现微信消息推送

    至于如何创建模板消息,如果获取模板id我这节就不再讲解,不知道的同学可以查看我上篇文章《借助云开发实现小程序订阅消息和模板消息的推送功能》里面有详细的讲解。

    编程小石头
  • LeetCode 1238. 循环码排列(格雷编码+旋转数组)

    给你两个整数 n 和 start。你的任务是返回任意 (0,1,2,,...,2^n-1) 的排列 p,并且满足:

    Michael阿明
  • SpringCloud 之 Zuul 源代码详细笔记

    alexqdjay
  • 一些Android util整理(唯一ID,加减乘除,清除缓存,Log工具类,Toast工具类)

    用户4458175
  • Guava-1.19类Predicates

    只要给定的参数是可序列化的,所有的方法返回可序列化的断言(predicates)。

    悠扬前奏

扫码关注云+社区

领取腾讯云代金券