1. jedis、lettuce、Redistemplate的关系

第一代为jedis,之后推出了lettuce,然后springboot继承了Redistemplate,现推荐使用Redistemplate。 总的来说,jedis、lettuce、Redistemplate都是java操作Redis数据库的驱动。

2. 本地Java连接Redis常见问题

bind配置注释掉保护模式设置为noLinux系统防火墙关掉Redis服务器 ip 端口 密码是否正确

3. jedis

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

3.1 建module

3.2 改pom

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">

4.0.0

com.atguigu.redis7

redis7_study

1.0-SNAPSHOT

org.springframework.boot

spring-boot-starter-parent

2.6.10

UTF-8

1.8

1.8

4.12

1.2.17

1.16.18

org.springframework.boot

spring-boot-starter-web

redis.clients

jedis

4.3.1

junit

junit

${junit.version}

org.springframework.boot

spring-boot-starter-test

test

log4j

log4j

${log4j.version}

org.projectlombok

lombok

${lombok.version}

true

org.springframework.boot

spring-boot-maven-plugin

3.3 写yml

server.port=7777

spring.application.name=redis7_study

3.4 主启动

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);

}

}

3.5 业务类

Demo

@Slf4j

public class JedisDemo

{

public static void main(String[] args)

{

Jedis jedis = new Jedis("192.168.111.185",6379);

jedis.auth("111111");

log.info("redis conn status:{}","连接成功");

log.info("redis ping retvalue:{}",jedis.ping());

jedis.set("k1","jedis");

log.info("k1 value:{}",jedis.get("k1"));

}

}

package com.atguigu.redis7.test;

import redis.clients.jedis.Jedis;

import java.util.*;

/**

* @auther zzyy

* @create 2022-11-17 16:39

*/

public class JedisDemo

{

public static void main(String[] args)

{

//连接本地的 Redis 服务,自己的ip和端口和密码

Jedis jedis = new Jedis("192.168.111.181",6379);

// 如果 Redis 服务设置了密码,需要下面这行,没有就不需要

jedis.auth("111111");

//key

Set keys = jedis.keys("*");

for (Iterator iterator = keys.iterator(); iterator.hasNext();) {

String key = (String) iterator.next();

System.out.println(key);

}

System.out.println("jedis.exists====>"+jedis.exists("k2"));

System.out.println(jedis.ttl("k1"));

//String

//jedis.append("k1","myreids");

System.out.println(jedis.get("k1"));

jedis.set("k4","k4_redis");

System.out.println("----------------------------------------");

jedis.mset("str1","v1","str2","v2","str3","v3");

System.out.println(jedis.mget("str1","str2","str3"));

//list

System.out.println("----------------------------------------");

//jedis.lpush("mylist","v1","v2","v3","v4","v5");

List list = jedis.lrange("mylist",0,-1);

for (String element : list) {

System.out.println(element);

}

//set

jedis.sadd("orders","jd001");

jedis.sadd("orders","jd002");

jedis.sadd("orders","jd003");

Set set1 = jedis.smembers("orders");

for (Iterator iterator = set1.iterator(); iterator.hasNext();) {

String string = (String) iterator.next();

System.out.println(string);

}

jedis.srem("orders","jd002");

System.out.println(jedis.smembers("orders").size());

//hash

jedis.hset("hash1","userName","lisi");

System.out.println(jedis.hget("hash1","userName"));

Map map = new HashMap();

map.put("telphone","138xxxxxxxx");

map.put("address","atguigu");

map.put("email","zzyybs@126.com");//课后有问题请给我发邮件

jedis.hmset("hash2",map);

List result = jedis.hmget("hash2", "telphone","email");

for (String element : result) {

System.out.println(element);

}

//zset

jedis.zadd("zset01",60d,"v1");

jedis.zadd("zset01",70d,"v2");

jedis.zadd("zset01",80d,"v3");

jedis.zadd("zset01",90d,"v4");

List zset01 = jedis.zrange("zset01", 0, -1);

zset01.forEach(System.out::println);

}

}

4. lettuce

4.1 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服务器中的数据之后而影响另一个线程的情况;

4.2 改pom

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">

4.0.0

com.atguigu.redis7

redis7_study

1.0-SNAPSHOT

org.springframework.boot

spring-boot-starter-parent

2.6.10

UTF-8

1.8

1.8

4.12

1.2.17

1.16.18

org.springframework.boot

spring-boot-starter-web

redis.clients

jedis

4.3.1

io.lettuce

lettuce-core

6.2.1.RELEASE

junit

junit

${junit.version}

org.springframework.boot

spring-boot-starter-test

test

log4j

log4j

${log4j.version}

org.projectlombok

lombok

${lombok.version}

true

org.springframework.boot

spring-boot-maven-plugin

4.3 业务类

package com.atguigu.redis7.test;

import io.lettuce.core.RedisClient;

import io.lettuce.core.RedisFuture;

import io.lettuce.core.RedisURI;

import io.lettuce.core.SortArgs;

import io.lettuce.core.api.StatefulRedisConnection;

import io.lettuce.core.api.async.RedisAsyncCommands;

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;

import java.util.concurrent.ExecutionException;

/**

* @auther zzyy

* @create 2022-11-17 17:05

*/

@Slf4j

public class LettuceDemo

{

public static void main(String[] args)

{

//使用构建器 RedisURI.builder

RedisURI uri = RedisURI.builder()

.redis("192.168.111.181")

.withPort(6379)

.withAuthentication("default","111111")

.build();

//创建连接客户端

RedisClient client = RedisClient.create(uri);

StatefulRedisConnection conn = client.connect();

//操作命令api

RedisCommands commands = conn.sync();

//keys

List list = commands.keys("*");

for(String s : list) {

log.info("key:{}",s);

}

//String

commands.set("k1","1111");

String s1 = commands.get("k1");

System.out.println("String s ==="+s1);

//list

commands.lpush("myList2", "v1","v2","v3");

List list2 = commands.lrange("myList2", 0, -1);

for(String s : list2) {

System.out.println("list ssss==="+s);

}

//set

commands.sadd("mySet2", "v1","v2","v3");

Set set = commands.smembers("mySet2");

for(String s : set) {

System.out.println("set ssss==="+s);

}

//hash

Map map = new HashMap<>();

map.put("k1","138xxxxxxxx");

map.put("k2","atguigu");

map.put("k3","zzyybs@126.com");//课后有问题请给我发邮件

commands.hmset("myHash2", map);

Map retMap = commands.hgetall("myHash2");

for(String k : retMap.keySet()) {

System.out.println("hash k="+k+" , v=="+retMap.get(k));

}

//zset

commands.zadd("myZset2", 100.0,"s1",110.0,"s2",90.0,"s3");

List list3 = commands.zrange("myZset2",0,10);

for(String s : list3) {

System.out.println("zset ssss==="+s);

}

//sort

SortArgs sortArgs = new SortArgs();

sortArgs.alpha();

sortArgs.desc();

List list4 = commands.sort("myList2",sortArgs);

for(String s : list4) {

System.out.println("sort ssss==="+s);

}

//关闭

conn.close();

client.shutdown();

}

}

5. Redistemplate 单机

5.1 建module

redis_study

5.2 改pom

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">

4.0.0

com.atguigu.redis7

redis7_study

1.0-SNAPSHOT

org.springframework.boot

spring-boot-starter-parent

2.6.10

UTF-8

1.8

1.8

4.12

1.2.17

1.16.18

org.springframework.boot

spring-boot-starter-web

redis.clients

jedis

4.3.1

io.lettuce

lettuce-core

6.2.1.RELEASE

org.springframework.boot

spring-boot-starter-data-redis

org.apache.commons

commons-pool2

io.springfox

springfox-swagger2

2.9.2

io.springfox

springfox-swagger-ui

2.9.2

junit

junit

${junit.version}

org.springframework.boot

spring-boot-starter-test

test

log4j

log4j

${log4j.version}

org.projectlombok

lombok

${lombok.version}

true

org.springframework.boot

spring-boot-maven-plugin

5.3 写yml

server.port=7777

spring.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

5.4 主启动

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.5 业务类

RedisConfig

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 RedisTemplate redisTemplate(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;

}

}

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();

}

}

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);

}

}

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);

}

}

5.6 测试

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

中文序列化问题 JDK 序列化方式 (默认) org.springframework.data.redis.serializer.JdkSerializationRedisSerializer , 默认情况下,RedisTemplate 使用该数据列化方式,我们来看下源码 RedisTemplate#afterPropertiesSet()

6. Redistemplate 集群

改写yml

server.port=7777

spring.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.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

模拟某台主机down掉,手动shutdown后会出现的问题

【故障演练】 Redis Cluster集群部署采用了3主3从拓扑结构,数据读写访问master节点, slave节点负责备份。当master宕机主从切换成功,redis手动OK,but 2个经典故障

如何解决

再次改写yml

server.port=7777

spring.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.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=2000

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

参考文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。