常州建设局职称网站,活动宣传推广的形式有哪些,开发板是干什么的,网站开发报价单#x1f697;Redis学习第三站~ #x1f6a9;起始站#xff1a;【Redis】概述环境搭建(一) #x1f6a9;本文已收录至专栏#xff1a;数据库学习之旅 #x1f44d;希望您能有所收获 在上一篇中我们学习了Redis常见命令的使用#xff0c;显然#xff0c;我们不可能一… Redis学习·第三站~ 起始站【Redis】概述环境搭建(一) 本文已收录至专栏数据库学习之旅 希望您能有所收获 在上一篇中我们学习了Redis常见命令的使用显然我们不可能一直通过指令去使用Redis。本篇我们一起学习如何使用Redis提供的Java客户端操作Redis。
一.概述
在Redis官网中提供了各种语言的客户端地址
其中Java客户端也包含了很多
标记为❤的就是推荐使用的java客户端包括
Jedis:以Redis命令作为方法名称(get,set…)学习成本低简单实用。但是Jedis实例是线程不安全的多线程环境下需要基于连接池来使用LettuceLettuce是基于Netty实现的支持同步、异步和响应式编程方式并且是线程安全的。支持Redis的哨兵模式、集群模式和管道模式SpringDataRedis:上述两个主要是提供了Redis命令对应的API方便我们操作Redis而SpringDataRedis又对这两种做了抽象和封装使得我们操作更加方便快捷。Redisson是在Redis基础上实现了分布式的可伸缩的java数据结构例如Map、Queue等而且支持跨进程的同步机制Lock、Semaphore等待比较适合用来实现特殊的功能需求。
二.Jedis客户端
Jedis的官网地址
Jedis使用的基本步骤 引入依赖 创建Jedis对象建立连接 使用Jedis方法名与Redis命令一致 释放资源
(1) 快速入门
使用Jedis需要先导入它的依赖我们可以先创建一个Maven工程然后引入如下依赖
!--jedis--
dependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion3.7.0/version
/dependency
!--单元测试--
dependencygroupIdorg.junit.jupiter/groupIdartifactIdjunit-jupiter/artifactIdversion5.7.0/versionscopetest/scope
/dependency新建一个单元测试类尝试与redis建立连接
private Jedis jedis;// 每次在执行其他测试方法前自动建立连接
BeforeEach
void setUp() {// 1.建立连接jedis new Jedis(192.168.150.101, 6379);// 2.设置密码jedis.auth(123321);// 3.选择库jedis.select(0);
}编写测试方法
Test
void testString() {// 存入数据方法名称就是redis命令名称非常简单String result jedis.set(name, zhangsan);System.out.println(result result);// 获取数据String name jedis.get(name);System.out.println(name name);
}Test
void testHash() {// 插入hash数据jedis.hset(user:1, name, Jack);jedis.hset(user:1, age, 21);// 获取MapString, String map jedis.hgetAll(user:1);System.out.println(map);
}通过上述测试代码我们可以看到使用Jedis客户端操作Redis和我们使用命令操作基本一致。 释放资源
// 每次在执行其他测试方法后自动关闭连接
AfterEach
void tearDown() {if (jedis ! null) {jedis.close();}
}(2) 使用连接池
Jedis本身是线程不安全的并且频繁的创建和销毁连接会有性能损耗因此我们推荐大家使用Jedis连接池代替Jedis的直连方式
有关池化思想并不仅仅是这里会使用很多地方都有比如说我们的数据库连接池比如我们tomcat中的线程池这些都是池化思想的体现。
package com.jedis.util;import redis.clients.jedis.*;public class JedisConnectionFactory {private static JedisPool jedisPool;static {// 配置连接池JedisPoolConfig poolConfig new JedisPoolConfig();// 最大连接 jedisPoolConfig.setMaxTotal(8); // 最大空闲连接 jedisPoolConfig.setMaxIdle(8); // 最小空闲连接 jedisPoolConfig.setMinIdle(0); // 设置最长等待时间 ms jedisPoolConfig.setMaxWaitMillis(200);// 创建连接池对象参数连接池配置、服务端ip、服务端端口、超时时间、密码jedisPool new JedisPool(poolConfig, 192.168.150.101, 6379, 1000, 123321);}public static Jedis getJedis(){return jedisPool.getResource();}
}代码说明 1 JedisConnectionFacotry工厂设计模式是实际开发中非常常用的一种设计模式我们可以使用工厂去降低代的耦合比如Spring中的Bean的创建就用到了工厂设计模式 2静态代码块(static)随着类的加载而加载确保只能执行一次我们在加载当前工厂类的时候就可以执行static的操作完成对 连接池的初始化 3最后提供返回连接池中连接的方法.
(3) 改造原始代码
我们可以不自己new而是通过JedisConnectionFacotry来获取jedis连接。 BeforeEachvoid setUp(){//建立连接// jedis new Jedis(127.0.0.1,6379);jedis JedisConnectionFacotry.getJedis();//选择库jedis.select(0);}Testvoid testString() {// 存入数据方法名称就是redis命令名称非常简单String result jedis.set(name, zhangsan);System.out.println(result result);// 获取数据String name jedis.get(name);System.out.println(name name);}AfterEachvoid tearDown() {if (jedis ! null) {jedis.close();}}代码说明:
1.在我们完成了使用工厂设计模式来完成代码的编写之后我们在获得连接时就可以通过工厂来获得而不用直接去new对象降低耦合并且使用的还是连接池对象。
2.当我们使用了连接池后当我们关闭连接其实并不是关闭而是将Jedis还回连接池的。
三.SpringDataRedis客户端
(1) 概述
SpringData是Spring中数据操作的模块包含对各种数据库的集成其中对Redis的集成模块就叫做SpringDataRedis官网地址
其有如下特点
提供了对不同Redis客户端的整合Lettuce和Jedis提供了RedisTemplate统一API来操作Redis支持Redis的发布订阅模型支持Redis哨兵和Redis集群支持基于Lettuce的响应式编程支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中 SpringBoot已经提供了对SpringDataRedis的支持使用非常简单。
使用步骤
引入spring-boot-starter-data-redis依赖在application.yml配置Redis信息在使用类中注入RedisTemplate
(2) 快速入门
首先新建一个SpringBoot工程在Maven中引入如下依赖 !--redis依赖--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency!--common-pool连接池--
dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId
/dependency2.在yml文件中 配置Redis连接相关信息
spring:redis:host: 192.168.150.101port: 6379password: 123321lettuce:pool:max-active: 8 #最大连接max-idle: 8 #最大空闲连接min-idle: 0 #最小空闲连接max-wait: 100ms #连接等待时间因为有了SpringBoot的自动装配我们可以在使用的地方直接注入RedisTemplate
SpringBootTest
class RedisStringTests {Resourceprivate RedisTemplate redisTemplate;
}新建测试类编写测试方法
SpringBootTest
class RedisStringTests {Resourceprivate RedisTemplate redisTemplate;Testvoid testString() {// 写入一条String数据redisTemplate.opsForValue().set(name, zhangsan);// 获取string数据Object name stringRedisTemplate.opsForValue().get(name);System.out.println(name name);}
}运行我们可以看到redisTemplate已经成功设置并获取到了数值
但是通过resp工具查看发现值的格式似乎有点问题这是为什么呢
(3) 对象序列化
RedisTemplate可以接收任意Object作为值写入Redis
只不过写入前会把Object序列化为字节形式默认是采用JDK序列化
因此我们得到的结果是这样的
缺点
可读性差内存占用较大
(3.1) 自定义序列化方式
我们可以自定义RedisTemplate的序列化方式代码如下
导入Jackson依赖使用springmvc时可不必我们引入 !--Jackson依赖--dependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactId/dependency自定义序列化器
Configuration
public class RedisConfig {Beanpublic RedisTemplateString, Object redisTemplate(RedisConnectionFactory connectionFactory){// 创建RedisTemplate对象RedisTemplateString, Object template new RedisTemplate();// 设置连接工厂template.setConnectionFactory(connectionFactory);// 创建JSON序列化工具GenericJackson2JsonRedisSerializer jsonRedisSerializer new GenericJackson2JsonRedisSerializer();// 设置Key的序列化template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());// 设置Value的序列化template.setValueSerializer(jsonRedisSerializer);template.setHashValueSerializer(jsonRedisSerializer);// 返回return template;}
}再次测试
SpringBootTest
class RedisStringTests {Resourceprivate RedisTemplateString,Object redisTemplate;Testvoid testString() {// 写入一条String数据redisTemplate.opsForValue().set(name, zhangsan);// 获取string数据Object name stringRedisTemplate.opsForValue().get(name);System.out.println(name name);}
}这次我们可以看到格式正常显示了。 但当我们存入对象是可能会碰到一些其他问题,例如:
SpringBootTest
class RedisDemoApplicationTests {Autowiredprivate RedisTemplateString,Object redisTemplate;Testvoid testSaveUser() {// 写入数据redisTemplate.opsForValue().set(user:1, new User(zhangsan, 21));// 获取数据User o (User) redisTemplate.opsForValue().get(user:1);System.out.println(o o);}
}
这里采用了JSON序列化来代替默认的JDK序列化方式。最终结果如图
整体可读性有了很大提升并且能将Java对象自动的序列化为JSON字符串并且查询时能自动把JSON反序列化为Java对象。不过其中记录了序列化时对应的class名称目的是为了查询时实现自动反序列化。这会带来额外的内存开销。
(3.2) 使用StringRedisTemplate
为了在反序列化时知道对象的类型JSON序列化器会将类的class类型写入json结果中存入Redis会带来额外的内存开销。
为了减少内存的消耗我们可以采用手动序列化的方式换句话说就是不借助默认的序列化器而是我们自己来控制序列化的动作同时我们只采用String的序列化器这样在存储value时我们就不需要在内存中就不用多存储数据从而节约我们的内存空间
为了节省内存空间我们可以不使用JSON序列化器来处理value而是统一使用String序列化器要求只能存储String类型的key和value。当需要存储Java对象时手动完成对象的序列化和反序列化。
因为存入和读取时的序列化及反序列化都是我们自己实现的SpringDataRedis就不会将class信息写入Redis了这样也就能实现我们的目的。
由于这种用法比较普遍因此SpringDataRedis就提供了RedisTemplate的子类StringRedisTemplate它的key和value的序列化方式默认就是String方式。
省去了我们自定义RedisTemplate的序列化方式的步骤而是直接使用
Resource
private StringRedisTemplate stringRedisTemplate;
// JSON序列化工具
private static final ObjectMapper mapper new ObjectMapper();Test
void testSaveUser() throws JsonProcessingException {// 创建对象User user new User(zhangsan, 21);// 使用序列化工具手动序列化也可以用gson,fastjson等等String json mapper.writeValueAsString(user);// 写入数据stringRedisTemplate.opsForValue().set(user:200, json);// 获取数据String jsonUser stringRedisTemplate.opsForValue().get(user:200);// 手动反序列化User user1 mapper.readValue(jsonUser, User.class);System.out.println(user1 user1);
}
此时我们再来看一看存储的数据小伙伴们就会发现那个class数据已经不在了节约了我们的空间~
(3.3) 小结
RedisTemplate的两种序列化实践方案 方案一 自定义RedisTemplate修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer 方案二 使用StringRedisTemplate写入Redis时手动把对象序列化为JSON读取Redis时手动把读取到的JSON反序列化为对象