前言
首先我们先知道类似于JDBC的连接中间件在redis之间使用的是啥
首先是Jedis,这是最初代的连接redis客户端
操作也是非常的简单
Jedis
首先我们先介绍这个
我们只需要引入对应的pom文件依赖
<!--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>
这个连接中间件主要是线程池不安全
所以才有了后续的迭代
我们先使用一下试试看
注意这里的端口和ip写自己的
如果不知道可以使用对应的命令进行查看
ifconfig //linux ipconfig //windows
public class JedisDemo { public static void main(String[] args) { //获得连接connect Jedis jedis = new Jedis("192.168.188.136", 6379); jedis.auth("abc123"); //获得客户端之后可以像JDBC一样可以获取 System.out.println(jedis.ping()); //获取keys * Set<String> keys = jedis.keys("*"); System.out.println(keys); //设置一个 jedis.set("k3","v333"); System.out.println(jedis.get("k3")); //list jedis.lpush("list","aaa","bbb","ccc"); System.out.println(jedis.lrange("list",0,-1)); } }
然后我们可以进对应的客户端查看就会发现对应的数据已经写入了
这里的乱码问题我们暂时不考虑,主要是编码和序列化的问题,是因为我之前测试集群输入中文的时候产生的,大家不必在意
Lettuce
有人会问有了Jedis为啥使用这个(中文翻译叫生菜)生菜呢?
其实是因为在使用Jedis的时候,会多次创建多个连接池
相对来说如果支持8w个请求,那么也肯定内内存撑爆了
而且其是线程不安全的
这里的Lettuce底层使用netty,可以确保只用一个连接池保证多路复用
说了这么多我们就来看看对应的Lettuce是怎么使用的吧
我们只需要对应的pom依赖导入
<!--lettuce--> <dependency> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> <version>6.2.1.RELEASE</version> </dependency>
这里主要体现链式编程,我们也是一样的配置
我们先配置对应的URL
在座位参数传给对应的客户端
然后创建对应操作command
public class LettuceDemo { public static void main(String[] args) { //1.使用构建器链式编程来构建redisURI RedisURI redisURI = RedisURI.builder() .redis("192.168.188.136") .withPort(6379) .withAuthentication("default", "abc123") .build(); //获取客户端 RedisClient redisClient = RedisClient.create(redisURI); StatefulRedisConnection<String, String> connect = redisClient.connect(); //创建操作的command RedisCommands<String, String> sync = connect.sync(); //业务操作 List<String> keys = sync.keys("*"); System.out.println(keys); //关闭资源 connect.close(); } }
虽然体现的日志信息比较多
但是也可以看到完整的信息
RedisTemplate(重中之重)
下面我们来介绍使用的主流
RedisTemplate,这也是被Spring集成的框架
我们可以在对应的jar包上看到起集成了Lettuce
其实是因为在Lettuce刚开发出来的时候Spring掩盖住了它的光芒
所以使用RedisTemplate更多
他还有一个常用的子类,叫做StringRedisTemplate
首先依然是引入对应的依赖
<!--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文件
注意修改ip为自己的ip哦
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
然后注意修改对应的主启动类
@SpringBootApplication public class Redis7Study7777 { public static void main(String[] args) { SpringApplication.run(Redis7Study7777.class,args); } }
我们这里采用一个微服务的架构,存储一个订单信息
架构大概是这样的
这里我们业务就在service层中写
@Service @Slf4j public class OrderService { public static final String ORDER_KEY = "order:"; @Resource private RedisTemplate redisTemplate; //@Resource //private StringRedisTemplate 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("添加订单成功,keyId:{},value:{}", keyId, value); } public String getOrder(int keyId) { return (String) redisTemplate.opsForValue().get(ORDER_KEY + keyId); } }
后面我们配置一下swagger直接测试接口
下面我们进行简单的get和add方法的书写以及swagger测试框架的配置
swagger配置
@Configuration @EnableSwagger2 public class SwaggerConfig { @Value("${spring.swagger2.enabled}") private Boolean enabled; @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .enable(enabled) .select() .apis(RequestHandlerSelectors.basePackage("org.example")) //你自己的package .paths(PathSelectors.any()) .build(); } }
对应的包记得改成自己的
然后我们写controller接口
@RestController @Slf4j @Api(tags ="订单接口") public class OrderController { @Resource private OrderService orderService; @ApiOperation("添加订单") @RequestMapping("/order/add") public void addOrder() { orderService.addOrder(); } @ApiOperation("查询订单") @RequestMapping("/order/{keyId}") public void getOrder(@PathVariable int keyId) { orderService.getOrder(keyId); } }
然后直接使用swagger进行对应的接口测试操作
这里为了演示一个错误,我们使用最原始的RedisTemplate
这时候我们就会发现写入的中文是乱码信息
解决方式这里提供两种方案
首先是使用StringRedisTemplate解决问题
因为默认RedisTemplate默认是采用对应的JDK来进行序列化的
我们使用StringRedisTemplate可以解决问题
但是我们查看对应的值还是不行
我们只需要在链接客户端的时候加上
redis-cli -a abc123 --raw
就可以解决中文乱码的问题了
如果就想使用RedisTemplate可以直接进行配置,在开始的时候就使用
StringRedisTemplate进行对应的初始化
只需要加上一个Config类
@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<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()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
即可解决问题
小总结
使用redis-cli -a "password" -p port --raw
就可以解决对应的中文乱码问题(根据键查看值的时候)
然后对应的序列化问题使用StringRedisTemplate就可以
注意swagger的包和对应的properties文件记得修改成自己的
集群操作配置
首先我们开启对应的集群
配置对应的配置信息
将单机的配置文件修改成对集群的
使用cluster nodes 查看对应的集群信息
我们试试对应的写入能否成功
# ========================redis集群===================== spring.redis.password=abc123 # 获取失败 最大重定向次数 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.188.136:6381,192.168.188.136:6382,192.168.188.137:6383,192.168.188.137:6384,192.168.188.138:6385,192.168.188.138:6386
我们尝试一下是否能成功写入
我们发现插入是成功的
我们再验证一下主从的上位情况是否能成功
我们先把主机干掉
我们尝试直接干掉138,查看136是否会上位
我们发现6382已经成为master了
然后我们再次尝试写入
我们发现一直失败了
然后到超时时间就直接失败了
我们可以配置对应的动态刷新拓扑结构或者是定时刷新就可以解决问题
因为这里其实是redis客户端的拓扑结构变化了
其实对应的微服务对其是无感应的
我们只需让其有感知即可
也就是对对应的配置文件进行修改
# ========================redis集群===================== spring.redis.password=abc123 #支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭 spring.redis.lettuce.cluster.refresh.adaptive=true #定时刷新 spring.redis.lettuce.cluster.refresh.period=2000 # 获取失败 最大重定向次数 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.188.136:6381,192.168.188.136:6382,192.168.188.137:6383,192.168.188.137:6384,192.168.188.138:6385,192.168.188.138:6386
其实还有两种方式,但是我们不推荐
1.底层使用Jedis
2.修改连接池的源码解决问题
解决完之后就是以下的结果