当前位置:   article > 正文

32、Redis 7系列:Spring Boot集成Redis

32、Redis 7系列:Spring Boot集成Redis

一、前言

本文只有集成 RedisTemplate ,也是市面上最推荐使用的。
集成 Jedis 和集成 lettuce 已经被淘汰,所以不做过多赘述~

二、集成 RedisTemplate

1、单机

(1)新建项目

此案例新建 spring boot 项目(新建 maven 项目也可以,不过需要手动添加基础pom依赖)
在这里插入图片描述

(2)修改pom文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ulanhada</groupId>
    <artifactId>redis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis</name>
    <description>redis</description>

    <!-- 依赖版本 -->
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <lombok.version>1.18.30</lombok.version>
        <log4j.version>1.2.17</log4j.version>
    </properties>

    <dependencies>
        <!--SpringBoot通用依赖模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <!--SpringBoot与Redis整合依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- spring boot 2.5.x后不需要引入Apache Commons Pool2 -->
<!--        <dependency>-->
<!--            <groupId>org.apache.commons</groupId>-->
<!--            <artifactId>commons-pool2</artifactId>-->
<!--        </dependency>-->

		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        
		<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

(3)修改yml文件

server:
  port=8080

spring:
  application:
    name: redis
  data:
    redis:
      database: 0
      host: 192.168.250.130
      port: 6379
      password: 123456
      lettuce:
        pool:
          max-active: 8
          max-wait: -1ms
          max-idle: 8
          min-idle: 0

# ========================logging=====================
logging:
  level:
    root: info
    com.ulanhada.redis: info
  pattern:
    console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n'
    file: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n'
  file:
    name: E:/redis/log/redis.log
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

(4)启动类

package com.ulanhada.redis;

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

@SpringBootApplication
public class RedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

(5)配置类

package com.ulanhada.redis.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @Description: // Redis序列化配置类
 * @Author: chnmayan
 * @Date: 2024-03-05 10:30
 */
@Configuration
public class RedisConfig {
	/**
     * @param lettuceConnectionFactory: 将配置文件中的redis配置,注入进工厂中。
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        //设置所有key序列化方式String
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        // 设置Hash的键(field)的序列化方式,只对Hash的field生效
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        // 设置Hash的值(value)的序列化方式,只对Hash的value生效
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

(6)业务类

UserController

package com.ulanhada.redis.controller;

import com.ulanhada.redis.service.UserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class UserController {

    @Resource
    UserService userService;

    @RequestMapping(value = "/user/add",method = RequestMethod.POST)
    public void addUser() {
        userService.addUser();
    }

    @RequestMapping(value = "/order/{userKey}", method = RequestMethod.GET)
    public String queryUserById(@PathVariable Integer userKey) {
        return userService.queryUserById(userKey);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

UserService

package com.ulanhada.redis.service;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

@Service
@Slf4j
public class UserService {

    public static final String USER_KEY = "userKey:";
    @Resource
    private RedisTemplate redisTemplate;

    public void addUser() {
        int userKey = ThreadLocalRandom.current().nextInt(1000);
        String userValue = UUID.randomUUID().toString().replace("-", "").toUpperCase();

        redisTemplate.opsForValue().set(USER_KEY + userKey,"用户ID:"+ userValue);
        log.info("======用户key:" + userKey + "; 用户ID:" + userValue);
    }

    public String queryUserById(Integer userKey) {
        return (String) redisTemplate.opsForValue().get(USER_KEY + userKey);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

(6)测试

第一步:无Redis配置类
首先启动项目。然后输入测试 url:localhost:8080/user/add
在这里插入图片描述
控制台输出:
在这里插入图片描述
登录 Redis 客户端验证:
为了更清楚的看清序列化,本次登录 Redis 客户端方式采用普通登录方式(不支持中文)。用 支持中文的方式 登录 Redis 客户端,会出现乱码。
在这里插入图片描述
上图说明数据已经新增成功。但是数据出现了序列化问题。
出现该问题的原因:
Redis 的键(key)和值(value)都是通过 Spring 提供的 Serializer 序列化到数据库的。
RedisTemplate 默认使用的是 JdkSerializationRedisSerializer
在这里插入图片描述
在这里插入图片描述
解决办法一:
编码中不使用 RedisTemplate ,改为 StringRedisTemplate
在这里插入图片描述
由于 StringRedisTemplate 已经指定了序列化方式,所以可以正常使用。不过该方法只能 String 的数据使用,其他数据类型不能使用。

解决办法二(推荐):
新建 Redis序列化配置类 。配置类内容见本文 (5)配置类
手动删除上一条数据,语法:del [key]
postman 重新新增一条数据,再次登录客户端验证。

# 语法:--raw: Redis客户端支持中文
redis-cli -a 123456 -p 6379 --raw
  • 1
  • 2

在这里插入图片描述

2、集群

(1)启动6台Redis实例(3主3从)

集群搭建不再赘述,不了解的小伙伴可以参考如下文章:
31、Redis 7系列:集群(cluster)
注意:登录客户端命令需要添加:-c--raw

redis-cli -a 123456 -p 6381 -c --raw
  • 1

在这里插入图片描述

(2)修改yml文件

yml文件Redis配置修改为集群

    redis:
      password: 123456
      lettuce:
        pool:
          max-active: 8
          max-wait: -1ms
          max-idle: 8
          min-idle: 0
      cluster:
        max-redirects: 3 # 获取失败 最大重定向次数
        nodes: 192.168.250.130:6381,192.168.250.130:6382,192.168.250.131:6383,192.168.250.131:6384,192.168.250.132:6385,192.168.250.132:6386
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

(3)测试(3主3从正常运行情况)

启动项目,并新增一条数据。
在这里插入图片描述

(4)测试(3主3从其中某台master突发宕机)

上文测试虽然新增成功,实则暗藏隐患。
如果当其中一台 master宕机 ,会出现什么情况?接下来做个深度测试。

  • 模拟 master-6381 服务器突发宕机
    执行 shutdown 命令

  • 查看集群信息
    发现 6384实例 原本是 6381实例slave 。目前已经变成 master
    在这里插入图片描述

  • 验证Redis客户端
    集群功能一切正常。
    在这里插入图片描述

  • 验证Spring Boot服务端
    由于本案例是基于Spring Boot 3.x,所以测试一切正常。
    在这里插入图片描述在这里插入图片描述

(5)拓展(根据上文测试)

本案例 Redis Cluster 集群部署采用了 3主3从拓扑结构 。数据读写访问 master 节点, slave 节点负责备份。当 master 宕机主从切换成功,Redis客户端 操作一切正常,Spring Boot服务端 会根据Spring Boot版本 的不同出现如下问题。
在这里插入图片描述

  • Spring Boot 1.x 版本环境
    Spring Boot 1.x 之前版本默认使用 jedis ,无需手动开启动态刷新。
  • Spring Boot 2.0~2.3 版本环境
    Spring Boot 2.0~2.3 版本默认使用 lettuce,默认不支持属性配置集群拓扑刷新。
  • Spring Boot 2.3之后 版本环境
    Spring Boot 2.3版本 之后版本默认使用 lettuce,默认支持属性配置开启集群拓扑刷新。
  • Spring Boot 3.x以后 版本环境
    默认动态的刷新集群拓扑感应。

解决办法:

  • 排除**lettuce** ,使用 jedis。更改pom文件(不推荐)
  • 重写连接工厂实例。(极度不推荐)
  • 动态的刷新集群拓扑感应。(推荐)
# 修改配置文件
spring:
  redis:
    lettuce:
      cluster:
        refresh-enabled: true #支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
        refresh-period: 2000 #定时刷新
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

到这里 Redis 7系列:Spring Boot集成Redis 就结束了!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/206522
推荐阅读
相关标签