第12章 SpringBoot集成Redis

Redis是一个高性能的开源的、C语言写的Nosql(非关系型数据库)。Redis通常用于数据缓存(Cache),作用是减少服务器业务代码对数据库的访问频率。简单的理解,就是将数据库查询的结果缓存到Redis中,等下次查询的时候,直接从Redis中获取数据,而不再查询数据了。因为Redis的内存存储比MySQL的硬盘存储要快的多。

如何安装Redis请查看:Windows安装Redis-优快云博客

首先,我们使用IDEA创建一个“SpringBootRedisDemo”的Maven工程。

然后我们修改编码格式以及Maven仓库地址,我们省略这个过程了。

接下来,我们修改 “pom.xml” 文件,添加SpringBoot和SpringBootRedis依赖,如下所示

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demo</groupId>
    <artifactId>SpringBootRedisDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.13</version>
        <relativePath/>
    </parent>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.18</version>
            </plugin>
        </plugins>
    </build>

</project>

接下来,我们创建 Appliaction 入口类文件

package com.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);
    }
}

接下来,我们要创建 application.properties 中配置Redis

spring.redis.host=127.0.0.1
spring.redis.port=6379
#spring.redis.password=123456
spring.redis.database=1

如果有连接密码的话,就设置上,没有就不用写了。注意,我们使用Redis中第1个数据库哦。

Redis的Java客户端常见的有jedis, redission,lettuce等等,所以我们在集成的时候,我们可以选择直接集成这些原生客户端。默认情况下,spring-boot-starter-data-redis 使用的就是lettuce这个客户端。

重点来了,spring-data-redis 为我们提供的 RedisTemplate 类来读写Redis缓存数据。

Redis中 string, list, hash,set, zset五种数据格式,都在RedisTemplate这个类中进行了封装。

RedisTemplate常用方法如下:

redisTemplate.opsForValue();		// 操作字符串
redisTemplate.opsForList();			// 操作list
redisTemplate.opsForHash();			// 操作hash
redisTemplate.opsForSet();			// 操作set
redisTemplate.opsForZSet();			// 操作有序set

redisTemplate.delete()				// 根据key删除

接下来,我们写入一个字符串类型

redisTemplate.opsForValue().set(key, value);

然后,我们创建一个 TestCache.java 类来测试一下

package com.demo.cache;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class TestCache {

    @Autowired
    private RedisTemplate redisTemplate;

    public void testSetStr(String key, String val){

        redisTemplate.opsForValue().set(key, val);
    }

    public String testGetStr(String key){

        return redisTemplate.opsForValue().get(key).toString();
    }
    
}

Redis中的数据以 key-value 形式保存在内存中,其value就是Redis中string, list, hash,set, zset五种数据格式。接下来,我们创建“TestController.java”控制器来调用上面的TestCache

package com.demo.controller;

import com.demo.cache.TestCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

@Controller
public class TestController {

    @Autowired
    private TestCache testCache;

    private final String key = "message";

    @RequestMapping("/testset")
    public String testset(String val, Map<String, Object> map){

        testCache.testSetStr(key, val);
        map.put("message", "");
        return "test";
    }

    @RequestMapping("/testget")
    public String testget(Map<String, Object> map){

        String msg = testCache.testGetStr(key);
        map.put("message", msg);
        return "test";
    }
    
}

接下来,我们创建 “resources\static\index.html” 和 “resources\templates\test.html” 视图文件

<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>index</title>
</head>
<body>

<a href="/testset?val=hello">testset?val=hello</a>
<br />
<a href="/testget">testget</a>

</body>
</html>
<!doctype html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>test</title>
</head>
<body>

<div th:text="${message}"></div>

</body>
</html>

我们整体工程的结构如下

我们运行一下,查看结果

此时已经将“message=hello”放入Redis中了。

可以查询到了,我们重复刷新页面的话,这个“hello”会一直存在的,直到我们删除或者Redis过期删除掉。我们可以通过 “RedisDesktopManager” 查看一下

对于缓存的数据,我们还可以删除它们,以及给他们设置缓存时间,如下所示:

    public void testDelStr(String key){

        redisTemplate.delete(key);
    }

    public void testSetStrExpire(String key, String val, long timeout){

        redisTemplate.opsForValue().set(key, val, timeout, TimeUnit.SECONDS);
    }

删除方法不用介绍了,设置缓存时间的话,我们可以指定时间数值和时间单位。

接下来,我们在“TestController.java”控制器中调用一下

    @RequestMapping("/testset")
    public String testset(String val, Map<String, Object> map){

        //testCache.testSetStr(key, val);
        testCache.testSetStrExpire(key, val, 300);
        map.put("message", "");
        return "test";
    }

    @RequestMapping("/testdel")
    public String testdel(Map<String, Object> map){

        testCache.testDelStr(key);
        map.put("message", "");
        return "test";
    }

接下来,我们在修改“index.html”文件

<a href="/testset?val=hello">testset?val=hello</a>
<br />
<a href="/testget">testget</a>
<br />
<a href="/testdel">testdel</a>

我们重新运行,测试一下

此时,缓存数据已经被我们删除了。我们直接查看“testget”请求页面

报错了,我们查看控制台日志

原因是,空指针异常,也就是我们的缓存数据不存在了。

    public String testGetStr(String key){

        if(redisTemplate.hasKey(key)){
            return redisTemplate.opsForValue().get(key).toString();
        }else{
            return "null";
        }
    }

我们做一个是否存在的操作即可。

接下来,我们重新缓存这个数据,也就是重新请求 “testset?val=hello” 页面,对数据缓存5分钟。

我们等待5分钟之后,刷新这个页面。

接下来,我们存储一个Java对象进去试试。

package com.demo.data;

import java.io.Serializable;

public class UserInfo implements Serializable {

    private int id;
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

我们定义了一个数据对象UserInfo类,它继承了 Serializable 序列化接口(必须的)。

    public void testSetObj(String key, UserInfo data){

        redisTemplate.opsForValue().set(key, data);
    }

    public UserInfo testGetObj(String key){

        return (UserInfo)redisTemplate.opsForValue().get(key);
    }

我们在 “testCache.java” 中增加缓存 UserInfo 类的方法。

    @RequestMapping("/testsetobj")
    public String testsetobj(Map<String, Object> map){

        UserInfo data = new UserInfo();
        data.setId(1);
        data.setName("张三");
        testCache.testSetObj(key, data);
        map.put("message", data.getName());
        return "test";
    }

    @RequestMapping("/testgetobj")
    public String testgetobj(Map<String, Object> map){

        UserInfo data = testCache.testGetObj(key);
        map.put("message", data.getName());
        return "test";
    }

我们在“testController.java”中调用上面的方法

<a href="/testset?val=hello">testset?val=hello</a>
<br />
<a href="/testget">testget</a>
<br />
<a href="/testdel">testdel</a>
<br />
<a href="/testsetobj">testsetobj</a>
<br />
<a href="/testgetobj">testgetobj</a>

添加入口连接之后,我们重新运行,测试一下

此时Java对象已经被缓存到Redis中了。

我们请求“testgetobj”页面也能看到了。

我们通过“RedisDesktopManager”去查看一下

默认是16进制显示,我们可以改成纯文本形式

大概也能看明白。

我们注意到 redisTemplate.opsForValue().set(key, data); 方法的data参数是一个泛型,它不仅支持字符串,也支持写入Object对象的。那么这个对象采取什么方式存入内存中就是它的序列化方式。spring-boot-starter-data-redis中使用JdkSerializationRedisSerializerl来实现序列化。这种序列化最大的问题就是存入对象后,我们很难直观看到存储的内容,很不方便我们排查问题。因此,我们需要修改一个RedisTemplate的序列化方式。目前比较流行的序列化方式,是将数据转成json格式进行缓存。因为json格式的字符串和Java对象可以进行相互转化。

首先,我们需要引入json库文件,这里我们使用阿里巴巴的fastjson库,它是阿里开源的一个高性能的JSON框架,FastJson支持序列化(把JavaBean对象转化成Json格式的字符串)和反序列化(把JSON格式的字符串转化为Java Bean对象)。

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>

接下来,我们增加一个配置类来修改Redis的默认序列化

package com.demo.config;

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@Configuration
public class RedisConfiguration {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(SecurityProperties.User.class);
        redisTemplate.setDefaultSerializer(fastJsonRedisSerializer);
        return redisTemplate;
    }

}

接下来,我们重新测试一下

缓存普通的字符串

缓存Java对象

现在,我们可以直观的看到缓存内容了。

完整 “SpringBootRedisDemo” 工程文件下载: https://download.youkuaiyun.com/download/richieandndsc/89904311

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值