第十二章、redis整合springboot
1、总体概述
1、有三个jar包目前市面常用
2、jedis:经典
3、lettuce:(生菜)优秀的产物,但是被RedisTemplate整合了
4、RedisTemplate:Spring家族整合的一个Redis连接工具
5、可以理解为jdbc连接数据库一样。以上3 个是连接redis的
2、本地java连接redis常见问题

3、springboot集成Jedis
1、是什么
1、jedis Client是Redis官网推荐的一个面向java的客户端,对Redis命令进行了封装的API
2、步骤
1、建module模块
1、就是建项目,一定要Maven的项目,不然难受死
2、改pom文件
1、改pom文件引入包
2、jedis包
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
3、本案例的所有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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.redis7</groupId>
<artifactId>redis7_study</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.10</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
<!--通用基础配置-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、编写yaml文件配置文件
1、如下
server.port=7777 #端口号
spring.application.name=redis7_study #模块名字
4、编写主启动类
1、如下
package com.atguigu.redis7;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @auther zzyy
* @create 2022-11-17 16:36
*/
@SpringBootApplication
public class Redis7Study7777
{
public static void main(String[] args)
{
SpringApplication.run(Redis7Study7777.class,args);
}
}
5、编写业务
1、五大基本数据类型
2、如下
package com.atguigu.redis7.demo;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JedisDemo {
public static void main(String[] args) {
// 通过connect连接指定的ip和端口号
Jedis jedis = new Jedis("192.168.171.129",6379);
// 指定访问服务器的密码
jedis.auth("111111");
System.out.println(jedis.ping());
// keys
Set<String> keys = jedis.keys("*");
System.out.println("keys = " + keys);
// list
jedis.hset("hash1","username","lisi");
System.out.println(jedis.hget("hash1","username"));
Map<String ,String > map = new HashMap<>();
map.put("password","123456");
map.put("age","20");
map.put("sex","男");
jedis.hset("hash1",map);
List<String > result = jedis.hmget("hash1","password","age","sex");
for (String res :result){
System.out.println(res);
}
System.out.println(jedis.hgetAll("hash1"));
// zset
jedis.zadd("zset01",60d,"v1");
jedis.zadd("zset01",70d,"v2");
jedis.zadd("zset01",80d,"v3");
jedis.zadd("zset01",90d,"v4");
List<String > zset01 = jedis.zrange("zset01",0,-1);
zset01.forEach(System.out::println);
}
}
4、springboot集成lettuce
1、是什么?
1、Lettuce是一个Redis的Java驱动包
2、lettuce比jedis有什么优势
1、springboot2.0默认用lettuce
2、jedis线程不安全(要手动关闭和大量创建线程)
3、lettuce底层用Netty,保证只创建一个连接线程,所以线程安全
3、步骤
1、添加pom文件
1、lettuce的jar包
<!--lettuce-->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.1.RELEASE</version>
</dependency>
2、本例中所用的所有jar包
<?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.atguigu.redis7</groupId>
<artifactId>redis7_study</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.10</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
<!--lettuce-->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.1.RELEASE</version>
</dependency>
<!--通用基础配置-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、配置文件
1、配置文件和整合jedis一样
3、启动类
1、启动类也和整合jedis一样
4、编写业务
1、用lettuce完成基本的5中数据类型
package com.atguigu.redis7.demo;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.SortArgs;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import java.util.*;
public class lettuceDemo {
public static void main(String[] args) {
// 1、使用构建器redisURI.builder
RedisURI uri = RedisURI.Builder
.redis("192.168.171.129")
.withPort(6379)
.withAuthentication("default","111111")
.build();
// 2、创建连接的客户端
RedisClient client = RedisClient.create(uri);
// 3、获取连接
StatefulRedisConnection conn = client.connect();
// 操作命令
RedisCommands<String ,String > commands = conn.sync();
// 编写业务逻辑
//keys
List<String > list = commands.keys("*");
for (String s :list){
System.out.println(s);
}
//string
System.out.println("String=====================");
commands.set("name","zhangsan");
commands.set("age","18");
String name = commands.get("name");
System.out.println("name = " + name);
String age = commands.get("age");
System.out.println("age = " + age);
//list
commands.lpush("mylist2","v1","v2","v3");
List<String > list2 = commands.lrange("mylist2",0,-1);
for(String s: list2){
System.out.println("sList ===== " + s);
}
//set
commands.sadd("myset2","v11","v22","v33");
Set<String> set = commands.smembers("myset2");
for(String s: set){
System.out.println("sSet = " + s);
}
//hash
Map<String ,String > map = new HashMap<>();
map.put("k1","v1hash");
map.put("k2","v2hash");
map.put("k3","v3hash");
commands.hset("myhash2",map);
Map<String,String> resmap = commands.hgetall("myhash2");
for(String k:resmap.keySet()){
System.out.println("k = " + k+"v=="+resmap.get(k));
}
//zset
commands.zadd("myzset2",1.0,"v1zset",2.0,"v2zset",3.0,"v3zset");
List<String > list3 = commands.zrange("myzset2",0,-1);
for(String s: list3){
System.out.println("sZset ==== " + s);
}
//sort
SortArgs sortArgs = new SortArgs();
sortArgs.alpha();
sortArgs.desc();
List<String > list4 = commands.sort("mylist2",sortArgs);
for(String s: list4){
System.out.println("sort ==== " + s);
}
// 4、关闭连接
conn.close();
client.shutdown();
}
}
5、springboot集成RedisTemplate
1、连接单机步骤
1、建模块
1、这里以redis7_study为例
2、改pom文件
1、这里只有第一个是必须,后面两个不是必须
<!--SpringBoot与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>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.redis7</groupId>
<artifactId>redis7_study</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.10</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
<!--lettuce-->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.1.RELEASE</version>
</dependency>
<!--SpringBoot与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>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--通用基础配置junit/devtools/test/log4j/lombok/hutool-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3、写yaml配置文件
1、本例中如下
## ========================redis单机=====================
#spring.redis.database=0
## 自己真实的IP
#spring.redis.host=192.168.171.129 #这个是reidsstuyd虚拟机的地址
#spring.redis.port=6379
#spring.redis.password=111111
#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
4、编写启动类
1、如下
package com.atguigu.redis7;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @auther zzyy
* @create 2022-11-17 16:36
*/
@SpringBootApplication
public class Redis7Study7777
{
public static void main(String[] args)
{
SpringApplication.run(Redis7Study7777.class,args);
}
}
5、配置类Config
1、这里要配置两个config
2、第一个是RedisConfig,这个东西是用来序列化的。如果不设置这个,写入redis和读出redis中的数据都是序列化乱码
-
package com.atguigu.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; /** * @auther zzyy * @create 2022-11-17 17:34 */ @Configuration public 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 */ @Bean public RedisTemplateredisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); //设置key序列化方式string redisTemplate.setKeySerializer(new StringRedisSerializer()); //设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化 redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } } -
如下图的乱码
-
3、配置SwaggerConfig
-
这个是用来方便测试用的
-
package com.atguigu.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; /** * @auther zzyy * @create 2022-11-17 17:44 */ @Configuration @EnableSwagger2 public class SwaggerConfig { @Value("${spring.swagger2.enabled}") private Boolean enabled; @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .enable(enabled) .select() .apis(RequestHandlerSelectors.basePackage("com.atguigu.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整合,有问题给管理员阳哥邮件:zzyybs@126.com") .version("1.0") .termsOfServiceUrl("https://www.atguigu.com/") .build(); } }
6、业务类
1、这里编写一个订单接口
1、接口包含添加订单、根据id查询订单,两个方法
1、service
package com.atguigu.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;
/**
* @auther zzyy
* @create 2022-07-14 15:11
*/
@Service
@Slf4j
public class OrderService
{
public static final String ORDER_KEY = "order:";
@Resource
private RedisTemplate redisTemplate;
public void addOrder()
{
int keyId = ThreadLocalRandom.current().nextInt(1000)+1;
String orderNo = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(ORDER_KEY+keyId,"京东订单"+ orderNo);
log.info("=====>编号"+keyId+"的订单流水生成:{}",orderNo);
}
public String getOrderById(Integer id)
{
return (String)redisTemplate.opsForValue().get(ORDER_KEY + id);
}
}
2、Controller
package com.atguigu.redis7.controller;
import com.atguigu.redis7.service.OrderService;
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 javax.annotation.Resource;
import java.util.concurrent.ThreadLocalRandom;
/**
* @auther zzyy
* @create 2022-07-14 15:08
*/
@Api(tags = "订单接口")
@RestController
@Slf4j
public class OrderController
{
@Resource
private OrderService orderService;
@ApiOperation("新增订单")
@RequestMapping(value = "/order/add",method = RequestMethod.POST)
public void addOrder()
{
orderService.addOrder();
}
@ApiOperation("按orderId查订单信息")
@RequestMapping(value = "/order/{id}", method = RequestMethod.GET)
public String findUserById(@PathVariable Integer id)
{
return orderService.getOrderById(id);
}
}
7、序列化问题
1、产生原因
- 这里RedisTemplate没有用StringSerializer的序列化。而是用Jdk的序列化
- 如图
2、连接集群
1、注意
1、问题一
-
Could not connect to Redis No route to host -
解决
-
关闭redis集群上,机器的防火墙
2、问题二
-
Node 192.168.171.129:6381 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0. -
解决
-
这个问题是因为我单机启动了redis,结果集群就发现,这么多个redis的数据不一致,所以。一定要保持数据一直! 我们可以把rdb和aof文件删了,然后重启就行
2、改写yaml配置文件
# ========================redis集群=====================
spring.redis.password=111111
# 获取失败 最大重定向次数
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=192.168.111.175:6381,192.168.111.175:6382,192.168.111.172:6383,192.168.111.172:6384,192.168.111.174:6385,192.168.111.174:6386
3、模拟人为宕机(问题)
1、人为关闭6379端口,
2、出现故障:springboot客户端没有动态感知到redisCluster的最新集群消息
- 如图
3、客户端访问出现问题

4、解决方法
1、方法一(不推荐)
1、我们把lettuce换掉,换成jedis
2、如图

2、方法二(不推荐)
1、重写连接工厂实例对象,除非你是大牛,否则不要作死
2、如下代码
//仅做参考,不写,不写,不写。
@Bean
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@Bean
public LettuceConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties, ClientResources clientResources) {
ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(30)) //按照周期刷新拓扑
.enableAllAdaptiveRefreshTriggers() //根据事件刷新拓扑
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
//redis命令超时时间,超时后才会使用新的拓扑信息重新建立连接
.timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(10)))
.topologyRefreshOptions(topologyRefreshOptions)
.build();
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
.clientResources(clientResources)
.clientOptions(clusterClientOptions)
.build();
RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
clusterConfig.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
clusterConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfig, clientConfiguration);
return lettuceConnectionFactory;
}
3、方法三(推荐)
1、我们设置yaml配置文件
2、如下
#支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
spring.redis.lettuce.cluster.refresh.adaptive=true
#定时刷新
spring.redis.lettuce.cluster.refresh.period=2000


