若依+redis基础
Redis
Redis是一个开源的由C语言开发的高性能键值对(key-value)数据库,是互联网技术领域使用最为广泛的存储中间件。
官方提供的数据表示可以达到100000+的QPS(每秒内查询次数)
QPS扩展:
- 小型应用
范围:10 - 100 QPS
特点:通常为初创公司或个人项目,用户基数较小,功能相对简单。
示例:博客平台、小型电商网站、内部工具。- 中型应用
范围:100 - 1,000 QPS
特点:有一定用户量,业务逻辑较为复杂,可能涉及多个服务和数据库。
示例:中型企业官网、中小型电商平台、在线教育平台。- 大型应用
范围:1,000 - 10,000 QPS
特点:用户量大,系统架构复杂,通常采用分布式架构和负载均衡。
示例:大型电商平台、社交网络、视频流媒体平台。- 超大型应用
范围:10,000+ QPS
特点:全球性用户,超高并发,使用微服务架构、CDN、缓存等技术优化性能。
示例:Google、Facebook、阿里巴巴、亚马逊等互联网巨头。NoSQL(Not Only SQL),泛指非关系型数据库,是对关系型数据库的补充
主要特点:
- 基于内存存储,读写性能高
- 适合存储热点数据(访问量高)
- 企业应用广泛(几乎没有不用)
图像化工具:Another Redis Desktop Manager 等;
常用数据类型与命令
常用数据类型:String(字符串),hash(哈希),list(列表),set(无序集合),zset(有序集合)
Redis中文网:https://www.redis.net.cn
String常用命令
| 命令 | 功能 |
|---|---|
| set key value | 设置指定KEY的值 |
| get key | 获取指定KEY的值 |
| setex key seconds value | 将值value关联到key,并将key的过期时间设为seconds(以秒为单位) |
| setnx key value | 只要在key不存在时设置key的值 |
| mset key value [key value ...] | 同时设置一个或多个 key-value 对 |
| msetnx key value [key value ...] | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在 |
| incr key | 将key中存储的数字值加一 |
| decr key | 将key中存储的数字值减一 |
其他数据类型对于的命令可以查看官方文档;
Spring Data Redis
Spring Data Redis 是 Spring 的一部分,在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
依赖引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
常用数据类型对于的相关API
字符串
/**
* 字符串 (String) 操作测试
* 展示如何使用 RedisTemplate 操作字符串数据类型
*/
@Test
public void stringTest() {
ValueOperations valueOperations = redisTemplate.opsForValue();
// 设置键 name 和 address 的值,并为 address 设置过期时间
valueOperations.set("name", "zhangsan");
valueOperations.set("address", "hangzhou", 3, TimeUnit.SECONDS);
// 条件性设置 gender 的值
valueOperations.setIfAbsent("gender", 1);
valueOperations.setIfAbsent("gender", 2);
// 打印键 name 和 address 的值
String name = (String) valueOperations.get("name");
System.out.println("name = " + name);
System.out.println(valueOperations.get("address"));
// 等待 3.5 秒后再次打印键 address 的值
ThreadUtil.sleep(3500);
System.out.println(valueOperations.get("address"));
// 设置并增加 age 的值
valueOperations.set("age", 18);
valueOperations.increment("age");
System.out.println(valueOperations.get("age"));
}
哈希
/**
* 哈希 (Hash) 操作测试
* 展示如何使用 RedisTemplate 操作哈希数据结构
*/
@Test
public void hashTest() {
HashMap<String, Object> map = new HashMap<>();
// 向哈希 user 中添加字段
map.put("name", "zhangsan");
map.put("age", 18);
map.put("address", "hangzhou");
redisTemplate.opsForHash().putAll("user", map);
// 打印哈希 user 中的 name 和 age 字段
System.out.println(redisTemplate.opsForHash().get("user", "name"));
System.out.println(redisTemplate.opsForHash().get("user", "age"));
// 打印哈希 user 中的所有字段名、值和键值对
System.out.println(redisTemplate.opsForHash().keys("user"));
System.out.println(redisTemplate.opsForHash().values("user"));
System.out.println(redisTemplate.opsForHash().entries("user"));
}
列表
/**
* 列表 (List) 操作测试
* 展示如何使用 RedisTemplate 操作列表数据结构
*/
@Test
public void listTest() {
// 向列表 location 中添加元素
redisTemplate.opsForList().rightPushAll("location", "hangzhou", "beijing", "shanghai");
// 打印列表 location 的大小和所有元素
System.out.println(redisTemplate.opsForList().size("location"));
System.out.println(redisTemplate.opsForList().range("location", 0, -1));
// 获取并打印列表 location 的第一个元素
redisTemplate.opsForList().index("location", 0);
System.out.println(redisTemplate.opsForList().leftPop("location"));
}
无序集合
/**
* 集合 (Set) 操作测试
* 展示如何使用 RedisTemplate 操作集合数据结构
*/
@Test
public void setTest() {
SetOperations setOperations = redisTemplate.opsForSet();
// 向集合 s1 和 s2 中添加元素
setOperations.add("s1", "java", "python", "network", "run", "dance");
setOperations.add("s2", "java", "python", "c#", "work", "sing");
// 打印集合 s1 的所有成员
System.out.println(setOperations.members("s1"));
// 随机移除并打印集合 s1 中的一个元素
System.out.println(setOperations.pop("s1"));
// 打印集合 s1 的大小
System.out.println(setOperations.size("s1"));
// 打印集合 s1 和 s2 的差集
System.out.println(setOperations.difference("s1", "s2"));
// 打印集合 s1 和 s2 的交集
System.out.println(setOperations.intersect("s1", "s2"));
// 计算集合 s1 和 s2 的并集并存储在 s3 中
setOperations.unionAndStore("s1", "s2", "s3");
// 打印集合 s3 的所有成员
System.out.println(setOperations.members("s3"));
}
有序集合
/**
* 有序集合 (ZSet) 操作测试
* 展示如何使用 RedisTemplate 操作有序集合数据结构
*/
@Test
public void zsetTest() {
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
// 向有序集合 phb 中添加元素
zSetOperations.add("phb", "zhangsan", 8000);
zSetOperations.add("phb", "lisi", 6500);
zSetOperations.add("phb", "wangwu", 18000);
zSetOperations.add("phb", "zhaoliu", 9000);
// 增加 zhangsan 的分数
zSetOperations.incrementScore("phb", "zhangsan", 2000);
// 打印有序集合 phb 中所有元素及其分数
Set<ZSetOperations.TypedTuple> phb = zSetOperations.reverseRangeWithScores("phb", 0, -1);
for (ZSetOperations.TypedTuple typedTuple : phb) {
System.out.println(typedTuple.getValue() + ":" + typedTuple.getScore());
}
}
通用命令
/**
* 基本操作测试
* 展示如何使用 RedisTemplate 进行基本的键值操作
*/
@Test
public void normalTest() {
// 打印所有键
System.out.println(redisTemplate.keys("*"));
// 设置键 phb 的过期时间为 1 分钟
redisTemplate.expire("phb", Duration.ofMinutes(1));
// 打印键 phb 的类型
System.out.println(redisTemplate.type("phb"));
// 检查键 s3 是否存在
System.out.println(redisTemplate.hasKey("s3"));
// 删除键 location 并打印结果
System.out.println(redisTemplate.delete("location"));
// 再次检查键 location 是否存在
System.out.println(redisTemplate.hasKey("location"));
}
若依中的Redis缓存使用
在若依框架中,使用了Redis作为缓存,并且以及进行了相关序列化配置
核心配置类为framework模块中的config.RedisConfig类
具体代码:
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
{
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
执行流程:
- 创建RedisTemplate实例:创建一个RedisTemplate<Object, Object>实例。
- 设置连接工厂:将传入的RedisConnectionFactory设置为该模板的连接工厂。
- 创建序列化器:
- 使用FastJson2JsonRedisSerializer作为值(value)的序列化器,确保对象可以被正确序列化和反序列化。
- 使用StringRedisSerializer来序列化和反序列化Redis的键(key)和哈希键(hash key),确保键以字符串形式存储。
- 设置序列化器:
- 设置键序列化器为StringRedisSerializer。
- 设置值序列化器为FastJson2JsonRedisSerializer。
- 设置哈希键序列化器为StringRedisSerializer。
- 设置哈希值序列化器为FastJson2JsonRedisSerializer。
- 初始化模板:调用afterPropertiesSet方法完成配置并返回配置好的RedisTemplate。
补充:在afterPropertiesSet方法中如果没有自己配置相关的序列化器,则会使用jdk默认的序列化器
JSON 序列化和 JDK 序列化的区别
FastJson2JsonRedisSerializer 使用的是 JSON 格式的序列化,而 JDK 序列化是 Java 内置的二进制序列化机制。它们在多个方面存在显著差异:
- 序列化格式
JDK 序列化:使用二进制格式进行序列化,生成的字节流包含类的元数据(如类名、字段信息等)。这种格式适合 Java 对象的持久化和传输,但不便于人类阅读。
JSON 序列化:使用 JSON 格式进行序列化,生成的是人类可读的文本字符串。JSON 是一种轻量级的数据交换格式,广泛用于 Web 开发和跨语言通信。 - 性能
JDK 序列化:相对较慢,因为需要处理大量的元数据,并且生成的二进制数据较大。此外,JDK 序列化在反序列化时对类版本敏感,如果类结构发生变化,可能会导致反序列化失败。
JSON 序列化:通常更快,尤其是在处理大量数据时,JSON 格式的解析和生成效率较高。FastJSON2 等高性能库进一步优化了 JSON 序列化的速度。 - 跨语言支持
JDK 序列化:只能用于 Java 程序之间的通信,因为它依赖于 Java 类的元数据。其他编程语言无法直接解析 JDK 序列化的二进制数据。
JSON 序列化:由于使用 JSON 格式,可以轻松与其他编程语言(如 JavaScript、Python、Go 等)进行数据交换,具有良好的跨语言兼容性。 - 可读性和调试
JDK 序列化:生成的二进制数据难以直接阅读和调试,需要专门的工具或反序列化才能查看内容。
JSON 序列化:生成的 JSON 字符串是人类可读的,方便调试和日志记录,可以直接查看和修改。 - 安全性
JDK 序列化:存在安全风险,特别是当反序列化不受信任的数据时,可能导致远程代码执行漏洞。因此,在使用 JDK 序列化时需要特别小心。
JSON 序列化:相对更安全,特别是在 FastJSON2 中可以通过配置白名单(如 JSONReader.autoTypeFilter)来限制允许反序列化的类型,从而减少安全风险。 - 灵活性
JDK 序列化:要求被序列化的类实现 Serializable 接口,并且类的结构不能随意更改,否则会导致反序列化失败。
JSON 序列化:更加灵活,不需要实现特定接口,且可以通过配置忽略某些字段或自定义序列化逻辑。

浙公网安备 33010602011771号