这篇文章让你详细了解Redis的相关知识,有代码讲解以及图片剖析,让你更轻松掌握
制作不易,感觉不错,请点赞收藏哟 !!!
目录
1 redis基础
1.1 定义
1.2 SQL和NOSQL不同点
1.3 特征
1.4 Redis通用命令
1.5 Redis数据结构介绍
1.6 Redis的java客户端
2 Jedis快速入门
2.1 操作步骤
2.2 Jedis连接池
3 SpringDataRedis
3.1 定义
3.2 优势
3.3 API
3.4 操作步骤
3.5 乱码解决方案
3.5.1 GenericJackson2JsonRedisSerializer优势
3.5.2 GenericJackson2JsonRedisSerializer缺陷
3.5.3 改进方案
3.5.4 RedisTemplate的两种序列化实践方案:
史诗级mysqlhttps://blog.csdn.net/2301_77358195/article/details/137121480
Redis诞生于2009年全称是Remote Dictionary Server,远程词典服务器,是一个基于内存的键值型NoSQL数据库。
①.数据结构:SQL是结构化的,NOSQL是非结构化的
②.数据关联:SQL是关联的,NOSQL是无关联的
③.查询方式:SQL是SQL查询,NOSQL是非SQL查询
④.事务特性:SQL是ACID,NOSQL是BASE
⑤.存储方式:SQL数据保存在磁盘,NOSQL数据保存在内存
①.键值(key-value)型,value支持多种不同数据结构,功能丰富
②.单线程,每个命令具备原子性
③.低延迟,速度快(基于内存、IO多路复用、良好的编码)。
④.支持数据持久化(会定期将内存数据保存到磁盘中)
⑤.支持主从集群、分片集群
⑥.支持多语言客户端
原子性(Atomicity)是指事务中的所有操作要么全部成功执行,要么全部失败回滚,不存在部分执行的情况。这确保了数据库在任何情况下都能保持一致性,即事务要么完全执行,要么完全不执行,不会出现中间状态。
①.KEYS:查看符合模板的所有keys,不建议在生产环境设备中使用(因为redis是单线程,当要查找的数据量很大时,redis服务会被阻塞)
,pattern可以是*,表示查找全部,a*表示查找以a开头的keys
②.DEL:删除一个指定的key
③.EXISTS:判断key是否存在
④.EXPIRE:给一个key设置有效期,有效期到期时该key会被自动删除
⑤.TTL:查看一个KEY的剩余有效期(-1表示永久有效,-2表示已被删除,整数代表还剩多长时间)
通过help [command] 可以查看一个命令的具体用法
Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样
数据类型的使用详细访问:https://www.redis.net.cn/tutorial/3508.html
基本数据类型:String、Hash、List、Set、SortedSet
特殊类型:GEO、BitMap、HelperLog
①.Jedis:以Redis命令作为方法名称,学习成本低。但是Jedis实例是线程不安全的,多线程环境下需要基于线程池来连接
②.Lettuce:Lettuce是基于Netty实现的,支持同步,异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式,集群和管道模式.
③.Spring Data Redis整合了这两个客户端,可以兼容Jedis,Lettuce,也就是说Spring Data Redis定义了一套API既可以用Jedis实现也可以用Lettuce实现
访问官方网址:https://redis.io/docs/connect/clients/java/jedis/#jedis
Jedis里面的API很类似原生Redis的相关指令,因此比较容易上手
①.引入依赖
②.建立连接
Jedis jedis = new Jedis("host","port");
jedis.auth("password");
③.测试方法
④.关闭资源(可以使用 try-with-resources
语法来确保 Jedis
在使用完毕后被自动关闭)
Jedis本身是不安全的,并且频繁的创建和销毁连接会有性能的损耗,因此推荐使用Jedis连接池代替Jedis的直连方式
注意:如果是连接池通过getJedis取出来Jedis,Jedis.close()方法不是直接断开,而是pool.returnResource(this),归还给连接池
public class JedisConnectionConfig {
private static final JedisPool jedisPool;
static {
//配置连接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//最大连接数
jedisPoolConfig.setMaxTotal(8);
//最大空闲时间
jedisPoolConfig.setMaxIdle(8);
//最小空闲连接
jedisPoolConfig.setMinIdle(0);
//设置最长等待时间,ms
jedisPoolConfig.setMaxWaitMillis(200);
//创建连接池对象
jedisPool = new JedisPool(jedisPoolConfig,"192.168.85.131",6379,1000,"root");
}
//获取Jedis对象
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
Spring Data Redis是Spring Data项目的一部分,旨在简化Spring应用程序中的数据访问。Spring Data Redis专门提供与Redis集成
官网地址:https://spring.io/projects/spring-data-redis
①.提供了对不同Redis客户端的整合(Lettuce和Jedis)
②.提供了RedisTemplate统一API来操作Redis
③.支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
④.支持基于Redis的JDKCollection实现
API 返回值类型 说明
opsForValue() ValueOperations 操作String类型
opsForHash() HashOperations 操作Hash类型
opsForList() ListOperations 操作List类型
opsForSet() SetOperations 操作Set类型
opsForZSet() ZSetOperations 操作SortedSet类型
redisTemplate 通用命令
①.引入依赖(需要两个依赖)
//Redis依赖
org.springframework.boot
spring-boot-starter-data-redis
//连接池依赖(因为Jedis和Lettuce底层都会基于commons-pool来实现连接池效果)
org.apache.commons
commons-pool2
②.配置文件
spring:
data:
redis:
host: localhost
port: 6379
#password: 123456
database: 0 #操作的是0号数据库
jedis: #如果不配置这一项,默认为Lettuce
#Redis连接池配置
pool:
max-active: 8 #最大连接数
max-wait: 1ms #连接池最大阻塞等待时间
max-idle: 4 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
③.注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
④.编写测试
SpringDataRedis的序列化方式
默认序列化器是 this.defaultSerializer = new JdkSerializationRedisSerializer,
如果你没有去实现其他序列化器,会导致中文乱码问题
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
//RedisTemplate 是一个通用的 Redis 操作模板,它支持对 Redis 中多种数据结构的操作
@Bean
public RedisTemplate
自己配置
因此一般key实现StringRedisSerializer序列化器,value实现GenericJackson2JsonRedisSerializer序列化器
实现如下图:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory){
// 创建RedisTemplate对象
RedisTemplate 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;
}
}
@Test
void testSaveUser() {
// 写入数据
redisTemplate.opsForValue().set("user:100", new User("大老鼠", 21));
// 获取数据
User o = (User) redisTemplate.opsForValue().get("user:100");
System.out.println("o = " + o);
}
GenericJackson2JsonRedisSerializer好处就是会将User对象序列化成JSON格式,然后
再将JSON格式序列化为@class里面的User对象,而这些都是自动化进行的
GenericJackson2JsonRedisSerializer通过上面这张图,也可以看出
GenericJackson2JsonRedisSerializer的缺陷,就是为了记录序列化的对象占用的内存比数据本身
还多,如果数据量很多的话,就不能突显redis的效率快特性
让key和value都实现StringRedisSerializer序列化器,然而这并不需要我们再去配置序列化器,
因为底层 StringRedisTemplate已经整合并实现了StringRedisSerializer序列化器,因此只需要
@Autowired
private StringRedisTemplate stringRedisTemplate;
但是序列化和反序列化要我们手动操作
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
// 创建对象
User user = new User("大老鼠", 21);
// 手动序列化
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);
}
方案一:
自定义RedisTemplate
修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
方案二(推荐):
使用StringRedisTemplate
写入Redis时,手动把对象序列化为JSON
读取Redis时,手动把读取到的JSON反序列化为对象
代码演示:
/**
序列化
*/
// 尝试从 Redis 中获取数据
String userJson = stringRedisTemplate.opsForValue().get(redisKey);
// 将对象序列化为 JSON 字符串
userJson = objectMapper.writeValueAsString(user);
// 将数据存储到 Redis 中,设置过期时间为 5 分钟
stringRedisTemplate.opsForValue().set(redisKey, userJson, 5, TimeUnit.MINUTES);
/**
反序列化
*/
// 示例 JSON 字符串
String userJson = "{\"id\":\"1\",\"name\":\"Alice\",\"age\":30}";
// 将 JSON 字符串反序列化为 User 对象
User user = objectMapper.readValue(userJson, User.class);
// 打印反序列化后的 User 对象
System.out.println("Deserialized User: ");
System.out.println("ID: " + user.getId());
System.out.println("Name: " + user.getName());
System.out.println("Age: " + user.getAge());