> 文章列表 > 【Redis学习】SpringBoot集成Redis

【Redis学习】SpringBoot集成Redis

【Redis学习】SpringBoot集成Redis

总体概述

jedis-lettuce-RedisTemplate三者的联系

  • 本地Java连接Redis常见问题

    bind配置请注释掉

    保护模式设置为no

    Linux系统的防火墙设置

    redis服务器的IP地址和密码是否正确

    忘记写访问redis的服务端口号和auth密码

集成jedis

简介

Jedis Client是Redis官网推荐的一个面向java的客户端,库文件实现了对各类API进行封装调用。

步骤

  • 建Module

    在这里插入图片描述

  • 改POM

    在这里插入图片描述

  • 写YML

    在这里插入图片描述

  • 主启动

    在这里插入图片描述

  • 业务类

public class JedisDemo {public static void main(String[] args) {// 1.connection获得,通过指定ip和端口号Jedis jedis = new Jedis("192.168.37.130", 6379);// 2.指定访问服务器的密码jedis.auth("123456");// 3.获得了jedis客户端,可以像jdbc一样,访问redisSystem.out.println(jedis.ping());//keysSet<String> keys = jedis.keys("*");System.out.println(keys);//stringjedis.set("k3", "hello,jedis");System.out.println(jedis.get("k3"));System.out.println(jedis.ttl("k3"));jedis.expire("k3", 20);//listjedis.lpush("list", "11", "12", "13");List<String> list = jedis.lrange("list", 0, -1);list.forEach(System.out::println);//setjedis.sadd("set1", "a", "b", "c");System.out.println(jedis.smembers("set1"));jedis.srem("set1", "b");System.out.println(jedis.smembers("set1").size());//hashjedis.hset("hs1", "name", "Pycro");System.out.println(jedis.hgetAll("hs1"));Map<String, String> map = new HashMap<>();map.put("age", "12");map.put("gender", "male");map.put("email", "123@qq.com");jedis.hset("hs1", map);System.out.println(jedis.hgetAll("hs1"));jedis.hdel("hs1", "age");System.out.println(jedis.hgetAll("hs1"));//zsetjedis.zadd("zs1", 60, "z1");jedis.zadd("zs1", 70, "z2");jedis.zadd("zs1", 80, "z3");Map<String, Double> zMap = new HashMap<>();zMap.put("z4", 90.0);zMap.put("z5", 100.0);jedis.zadd("zs1", zMap);System.out.println(jedis.zrangeWithScores("zs1", 0, -1));}
}
/*
PONG
[hs1, zs1, set1, list]
hello,jedis
-1
13
12
11
13
12
11
13
12
11
13
12
11
[a, b, c]
2
{name=Pycro, gender=male, email=123@qq.com}
{name=Pycro, gender=male, email=123@qq.com, age=12}
{name=Pycro, gender=male, email=123@qq.com}
[[z1,60.0], [z2,70.0], [z3,80.0], [z4,90.0], [z5,100.0]]
*/

集成lettuce

简介

Lettuce是一个Redis的Java驱动包,Lettuce翻译为生菜,没错,就是吃的那种生菜,所以它的Logo长这样。

在这里插入图片描述

在这里插入图片描述

lettuce VS jedis

Jedis:开销大,线程不安全

Lettuce:开销小,线程安全

案例

  • 改POM

    在这里插入图片描述

  • 业务类

public class LettuceDemo {public static void main(String[] args) {//1.使用构建器链式编程builder出RedisURIRedisURI uri = RedisURI.Builder.redis("192.168.37.130").withPort(6379).withAuthentication("default", "123456").build();//2.创建连接客户端RedisClient redisClient = RedisClient.create(uri);StatefulRedisConnection<String, String> conn = redisClient.connect();//3.通过conn创建操作的commandRedisCommands<String, String> commands = conn.sync();//=====================================//keysList<String> keys = commands.keys("*");System.out.println("" + keys);//stringcommands.set("k5", "hello,lettuce");System.out.println("" + commands.get("k5"));//listSystem.out.println("" + commands.lrange("list", 0, -1));//hashSystem.out.println("" + commands.hgetall("hs1"));//setSystem.out.println("" + commands.smembers("set1"));//zsetSystem.out.println("" + commands.zrange("zs1", 0, -1));//=====================================//4.各种关闭释放资源conn.close();redisClient.shutdown();}
}

RedisTemplate(推荐使用)

连接单机

建Module

  • 改POM

    在这里插入图片描述

  • 写YML

server.port=7777
spring.application.name=Redis7
# ===loggging===
logging.leve1.root=info
1ogging.leve1.usts.pycro.redis7=info
logging.pattern.console=%d{yyyy-M-dd HH:mm:ss.sSS} [%thread] %-5level %logger -%msg%n
1ogging.file.name=redis7.log
logging.pattern.file=%d{yyyy-MW-dd HH:mm:ss.sss} [%thread]%-5level %logger -%msg%n
# ===Swagger========
spring.swagger2.enabled=true
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# ======redis单机=======
spring.redis.database=0
spring.redis.host=centos
spring.redis.port=6379
spring.redis.password=123456
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.poo1.max-wait=-1ms
spring.redis.lettuce.poo1.max-idle=8
spring.redis.lettuce.pool.min-idle=0
  • 主启动
  @SpringBootApplicationpublic class Redis7Application {public static void main(String[] args) {SpringApplication.run(Redis7Application.class, args);}}
  • 业务类

    • 配置类
//故意先空着
package usts.pycro.redis7.config;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;/* @author Pycro* @version 1.0* 2023-04-06 11:30 PM*/@Configuration@EnableSwagger2public class SwaggerConfig {@Value("${spring.swagger2.enabled}")private Boolean enabled;@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).enable(enabled).select().apis(RequestHandlerSelectors.basePackage("usts.pycro.redis7")) //你自己的package.paths(PathSelectors.any()).build();}public ApiInfo apiInfo() {return new ApiInfoBuilder().title("springboot利用swagger2构建api接口文档 " + "\\t" + DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now())).description("springboot+redis整合,问题反馈邮件:pycro@126.com").version("1.0").termsOfServiceUrl("https://www.usts.edu.cn/").build();}}
  • service
package usts.pycro.redis7.service;import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;/* @author Pycro* @version 1.0* 2023-04-07 9:16 AM*/@Service@Slf4jpublic class OrderService {public static final String ORDER_KEY = "ord:";@Resourceprivate RedisTemplate redisTemplate;public void addOrder() {int keyId = ThreadLocalRandom.current().nextInt(1000) + 1;String serialNo = UUID.randomUUID().toString();String key = ORDER_KEY + keyId;String value = "京东订单" + serialNo;redisTemplate.opsForValue().set(key, value);log.info("*key:{}", key);log.info("*value:{}", value);}public String getOrderById(Integer keyId) {return (String) redisTemplate.opsForValue().get(ORDER_KEY + keyId);}}
  • controller
package usts.pycro.redis7.controller;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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;
import usts.pycro.redis7.service.OrderService;import javax.annotation.Resource;/* @author Pycro* @version 1.0* 2023-04-07 9:26 AM*/@RestController@Slf4j@Api(tags = "订单接口")public class OrderController {@Resourceprivate OrderService orderService;@ApiOperation("新增订单")@RequestMapping(value = "/order/add", method = RequestMethod.POST)public void addOrder() {orderService.addOrder();}@ApiOperation("按照keyId查询订单")@RequestMapping(value = "/order/{keyId}", method = RequestMethod.GET)public void getOrderById(@PathVariable Integer keyId) {orderService.getOrderById(keyId);}}
  • 测试

    地址:http://localhost:7777/swagger-ui.html#

    • 序列化问题

      解决方案1:使用StringRedisTemplate

      在这里插入图片描述

      JDK序列化方式(默认)惹的祸,需要在RedisConfig中配置

package usts.pycro.redis7.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;/* @author Pycro* @version 1.0* 2023-04-06 11:29 PM*/@Configurationpublic class RedisConfig{/* redis序列化的工具配置类,下面这个请一定开启配置* 127.0.0.1:6379> keys  1) "ord:102"  序列化过* 2) "\\xac\\xed\\x00\\x05t\\x00\\aord:102"   野生,没有序列化过* this.redisTemplate.opsForValue(); //提供了操作string类型的所有方法* this.redisTemplate.opsForList(); // 提供了操作list类型的所有方法* this.redisTemplate.opsForSet(); //提供了操作set的所有方法* this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法* this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法* @param lettuceConnectionFactory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}}

连接集群

  • 启动redis集群6台实例

    在这里插入图片描述

  • 第一次改写YML

# ========redis集群========
spring.redis.password=123456
# 获取失败,最大重定向次数
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.cluster.nodes=centos:6381,centos:6382,centos:6383,centos:6384,centos:6385,centos:6386
  • 直接通过微服务访问redis集群

    http://localhost:7777/swagger-ui.html#/订单接口

    一切OK

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  • 问题来了

    人为模拟,master-6381机器意外宕机,手动shutdown

    先对redis集群命令方式,手动验证各种读写命令,看看6384是否上位——Y

    Redis Cluster集群能自动感知并自动完成主备切换,对应的slave6384会被选举为新的master

    • 微服务客户端再次读写访问试试

      在这里插入图片描述

      在这里插入图片描述

      • 故障现象

        SpringBoot客户端没有动态感知到RedisCluster的最新集群信息

        经典故障:Connection refused: no further information: /192.168.37.130:6381

      • 导致原因

        SpringBoot 2.X版本, Redis默认的连接池采用Lettuce

        当Redis集群节点发生变化后,Letture默认是不会刷新节点拓扑

      • 解决方案

        1. 排除lettuce采用jedis(不推荐)

        2. 重写连接工厂实例(极度不推荐)

        3. 刷新节点集群拓扑动态感应

        在这里插入图片描述

        在这里插入图片描述

      • 第二次改写YML

#支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
spring.redis.lettuce.cluster.refresh.adaptive=true
#定时刷新
spring.redis.lettuce.cluster.refresh.period=2000