> 文章列表 > 【Redis7】Spring Boot集成Redis(重点:集成RedisTemplate)

【Redis7】Spring Boot集成Redis(重点:集成RedisTemplate)

【Redis7】Spring Boot集成Redis(重点:集成RedisTemplate)

【大家好,我是爱干饭的猿,本文重点介绍Redis7 Spring Boot集成Redis,包括Jedis、lettuce、集成RedisTemplate、集群时一台master宕机,java报错的情况分析。

后续会继续分享Redis7和其他重要知识点总结,如果喜欢这篇文章,点个赞👍,关注一下吧】

上一篇文章:《【Redis7】Redis7 集群(重点:哈希槽分区)》


目录

🍖1. redis 配置文件

🍖2.Jedis

2.1 介绍

2.2 操作使用

🍖3. lettuce 

3.1 介绍

3.2 Jedis和Lettuce的区别

3.3 操作使用

🍖4. 集成RedisTemplate - 推荐使用

4.1 连接单机

1. 操作使用

2. 测试

4.2 连接集群

1.正常启动

2. 测试

3. 一台master宕机,java报错


🍖1. redis 配置文件

  • redis.conf配置文件,改完后确保生效,记得重启,记得重启
    • 默认daemonize no 改为 daemonize yes
    • 默认protected-mode yes 改为 protected-mode no
    • 默认bind 127.0.0.1 改为 直接注释掉(默认bind 127.0.0.1只能本机访问)或改成本机IP地址,否则影响远程IP连接
    • 添加redis密码 改为 requirepass 你自己设置的密码

🍖2.Jedis

2.1 介绍

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

2.2 操作使用

  • 新建项目

  • pom.xm

		<!--jedis--><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.3.1</version></dependency>
  • yml文件

server.port=7777spring.application.name=redis7_study
  • 业务类
package com.haomin.redis7_study.jedis_lettuce;import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import java.util.*;/*** @author haomin* @date 2023/04/22 11:32**/
@Slf4j
public class JedisDemo {public static void main(String[] args) {Jedis jedis = new Jedis("**.***.***.***", 6379);jedis.auth("***");log.info("redis conn status:{}", "连接成功");log.info("redis ping retvalue:{}", jedis.ping());jedis.set("k1","v1");jedis.set("k2","v2");jedis.set("k3","v3");Set<String> keys = jedis.keys("*");for (String key : keys) {System.out.println(key);}// Stringjedis.mset("m1", "v1","m2","v2","m3","v3");System.out.println(jedis.mget("m1", "m2","m3"));// listjedis.lpush("myList","v1","v2","v3","v4","v5");System.out.println(jedis.lrange("myList", 0, -1));// setjedis.sadd("orders","111");jedis.sadd("orders","222");jedis.sadd("orders","333");Set<String> set1 = jedis.smembers("orders");for(Iterator iterator = set1.iterator(); iterator.hasNext();) {String string = (String) iterator.next();System.out.println(string);}jedis.srem("orders","222");System.out.println(jedis.smembers("orders").size());//hashjedis.hset("hash1","userName","lisi");System.out.println(jedis.hget("hash1","userName"));Map<String,String> map = new HashMap<String,String>();map.put("telphone","138xxxxxxxx");map.put("address","atguigu");map.put("email","zzyybs@126.com");//课后有问题请给我发邮件jedis.hmset("hash2",map);List<String> result = jedis.hmget("hash2", "telphone","email");for (String element : result) {System.out.println(element);}//zsetjedis.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);}
}

🍖3. lettuce 

3.1 介绍

Lettuce是一个Redis的Java驱动包,Lettuce翻译为生菜

3.2 Jedis和Lettuce的区别

        jedis和Lettuce都是Redis的客户端,它们都可以连接Redis服务器,但是在SpringBoot2.0之后默认都是使用的Lettuce这个客户端连接Redis服务器。因为当使用Jedis客户端连接Redis服务器的时候,每个线程都要拿自己创建的Jedis实例去连接Redis客户端,当有很多个线程的时候,不仅开销大需要反复的创建关闭一个Jedis连接,而且也是线程不安全的,一个线程通过Jedis实例更改Redis服务器中的数据之后会影响另一个线程。

        但是如果使用Lettuce这个客户端连接Redis服务器的时候,就不会出现上面的情况,Lettuce底层使用的是Netty,当有多个线程都需要连接Redis服务器的时候,可以保证只创建一个Lettuce连接,使所有的线程共享这一个Lettuce连接,这样可以减少创建关闭一个Lettuce连接时候的开销;而且这种方式也是线程安全的,不会出现一个线程通过Lettuce更改Redis服务器中的数据之后而影响另—个线程的情况。

3.3 操作使用

  • pom.xml
		<!--lettuce--><dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.2.1.RELEASE</version></dependency>
  • 业务类
package com.haomin.redis7_study.jedis_lettuce;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 lombok.extern.slf4j.Slf4j;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** @author haomin* @date 2023/04/22 16:39**/
@Slf4j
public class LettuceDemo {public static void main(String[] args) {// 1.使用构建器链式编程来builder我们RedisURIRedisURI uri = RedisURI.builder().redis("**.***.***.***").withPort(6379).withAuthentication("default", "***").build();// 2.创建连接客户端RedisClient client = RedisClient.create(uri);StatefulRedisConnection conn = client.connect();// 3.通过conn创建操f作的comnandRedisCommands<String, String> commands = conn.sync();//===================操作=======================// keysList<String> list = commands.keys("*");for (String s : list) {log.info("key:{}", s);}commands.set("k1","1111");String s1 = commands.get("k1");System.out.println("String s ==="+s1);//listcommands.lpush("myList2", "v1","v2","v3");List<String> list2 = commands.lrange("myList2", 0, -1);for(String s : list2) {System.out.println("list ssss==="+s);}//setcommands.sadd("mySet2", "v1","v2","v3");Set<String> set = commands.smembers("mySet2");for(String s : set) {System.out.println("set ssss==="+s);}//hashMap<String,String> map = new HashMap<>();map.put("k1","111");map.put("k2","222");map.put("k3","333");commands.hmset("myHash2", map);Map<String,String> retMap = commands.hgetall("myHash2");for(String k : retMap.keySet()) {System.out.println("hash  k="+k+" , v=="+retMap.get(k));}//zsetcommands.zadd("myZset2", 100.0,"s1",110.0,"s2",90.0,"s3");List<String> list3 = commands.zrange("myZset2",0,10);for(String s : list3) {System.out.println("zset ssss==="+s);}//sortSortArgs sortArgs = new SortArgs();sortArgs.alpha();sortArgs.desc();List<String> list4 = commands.sort("myList2",sortArgs);for(String s : list4) {System.out.println("sort ssss==="+s);}//===================操作=======================//4. 关闭conn.close();client.shutdown();}
}

🍖4. 集成RedisTemplate - 推荐使用

4.1 连接单机

1. 操作使用

  • pom.xml
		<!--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>
  • yml
server.port=7777spring.application.name=redis7_study# ========================logging=====================
logging.level.root=info
logging.level.com.atguigu.redis7=info
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n logging.file.name=D:/mylogs2023/redis7_study.log
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n# ========================swagger=====================
spring.swagger2.enabled=true
#在springboot2.6.X结合swagger2.9.X会提示documentationPluginsBootstrapper空指针异常,
#原因是在springboot2.6.X中将SpringMVC默认路径匹配策略从AntPathMatcher更改为PathPatternParser,
# 导致出错,解决办法是matching-strategy切换回之前ant_path_matcher
spring.mvc.pathmatch.matching-strategy=ant_path_matcher# ========================redis单机=====================
spring.redis.database=0
# 修改为自己真实IP
spring.redis.host=192.168.111.185
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
  • 业务类

  • config.redisConfig
package com.haomin.redis7_study.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 haomin* @date 2023/04/22 17:28**/
@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*/@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;}
}
  • config.SwaggerConfig
package com.haomin.redis7_study.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 haomin* @date 2023/04/22 17:28**/
@Configuration
@EnableSwagger2
public 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("com.haomin.redis7_study")) //你自己的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整合").version("1.0").termsOfServiceUrl("https://haomin.blog.csdn.net/").build();}
}
  • controller.OrderController
package com.haomin.redis7_study.controller;import com.haomin.redis7_study.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;/*** @author haomin* @date 2023/04/22 17:52**/
// 访问:http://localhost:7777/swagger-ui.html#/@Api(tags = "订单接口")
@RestController
@Slf4j
public class OrderController
{@Resourceprivate 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);}
}
  • service.OrderService
package com.haomin.redis7_study.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 haomin* @date 2023/04/22 17:28**/@Service
@Slf4j
public class OrderService {public static final String ORDER_KEY = "order:";@Resourceprivate 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. 测试

访问:访问:http://localhost:7777/swagger-ui.html#/

  • 如果使用RedisTemplate,推荐序列化用StringRedisSerializer,默认使用的是JdkSerializationRedisSerializer,存入Redis会出现乱码问题,查询非常不方便

4.2 连接集群

1.正常启动

  • 启动前面配的集群

  • 改写YML(注意IP和端口)

# ========================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=***.***.***.***:6381,***.***.***.***:6382 (主机:port)

2. 测试

访问:访问:http://localhost:7777/swagger-ui.html#/

3. 一台master宕机,java报错

  • 让master-6381宕机,shutdown

  • 查看集群信息 ,看slave是否上位 Cluster nodes

  • 我们客户端再次读写

  • 原因是因为SpringBoot客户端没有动态感知到RedisCluster的最新集群信息

  • 导致这个的原因是

    • Spring Boot 2,Redis默认的是 Lettuce
    • 当Redis集群节点发生变化后,Lettuce默认是不会刷新节点拓扑
  • 解决方法:

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

      1.  

    2. 排除Lettuce采用jedis(不推荐)

    3. 刷新节点结群拓扑和动态感应(推荐)

      • 修改pom.xml

      • # ========================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# ========================新增=====================
        #支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
        spring.redis.lettuce.cluster.refresh.adaptive=true
        #定时刷新
        spring.redis.lettuce.cluster.refresh.period=2000spring.redis.cluster.nodes=***.***.***.***:6381,***.***.***.***:6382 (主机:port)

reids初级篇分享到此,感谢大家观看!!!

如果你喜欢这篇文章,请点赞关注吧,或者如果你对文章有什么困惑,可以私信我。

🏓🏓🏓

全国邮编查询网