SpringBoot使用redis解决分页查询大量数据慢的情况
SpringBoot使用redis解决分页查询大量数据慢的情况
数据量大的时候,即使分页查询速度也会变慢
用缓存:提前把数据取出来保存好(通常保存到读写更快的介质,比如内存),就可以更快地读写。
缓存的实现
分布式缓存
- Redis(分布式缓存)
- memcached(分布式)
- Etcd(云原生架构的一个分布式存储,存储配置,扩容能力)
java的进程缓存
-
ehcache(单机)
-
本地缓存(Java 内存 Map)
-
Caffeine(Java 内存缓存,高性能)
-
Google Guava
单机缓存
数据不一致
解决方法:主从复制
分布式缓存
Redis可以作为分布式缓存
Redis
NoSQL数据库
key-value存储系统(区别于MySQL存储的键值对)
Java里的实现方式
- Spring Data Redis
- Jedis
- Redisson
Spring Data Redis(推荐)
通用的数据访问框架、提供了一组增删改查的接口
操作mysql、redis
引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.6.3</version>
</dependency>
yml
spring:
redis:
host: localhost
port: 6379
database: 0
Redis的数据结构
String 字符串类型:name:“aaa”
List列表:names:[“aaa”,“aab”,“aaa”]
Set集合: names:[“aa”,“ab”]
Hash哈希:nameAge:{“aa”:1,“dd”:2}
Zset集合:names:{aaa-9,bbb-12}适合做排行榜
redis也可以做消息队列
bloomfilter(布隆过滤器,主要从大量的数据中快速过滤值,比如邮件黑名单拦截)
geo(计算地理位置)
hyperloglog(pv / uv)
pub / sub(发布订阅,类似消息队列)
BitMap (1001010101010101010101010101)
测试一下
package com.bo.partner.service;
import com.bo.partner.model.domain.User;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author: bo
* @date: 2022/9/12
* @description:
*/
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testRedis() {
ValueOperations value = redisTemplate.opsForValue();
value.set("aaaString", "aka");
value.set("aaaint", 1);
value.set("aaadouble", 2.0);
User user = new User();
user.setId(1L);
user.setUsername("aaa");
value.set("aauser",user);
Object aaaString = value.get("aaaString");
Assertions.assertTrue("aka".equals((String)aaaString));
Object aaaint = value.get("aaaint");
Assertions.assertTrue(1==((Integer)aaaint));
Object aaadouble = value.get("aaadouble");
Assertions.assertTrue(2.0==((Double)aaadouble));
System.out.println(value.get("aauser"));
}
}
报错,空指针异常,解决方法:加个注解@RunWith(SpringRunner.class)
用quickredis查看
怎么回事
看看redisTempalte干了什么
redisTemplate序列化了
if序列化器是空,用的java原生的序列化器
我们加个泛型
@Resource
private RedisTemplate<String, Object> redisTemplate;
没什么用
我们用StringRedisTemplate
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
public void testRedis() {
ValueOperations value = stringRedisTemplate.opsForValue();
但是其他类型的不行了
注释掉其他的
成功
但是没有其他的实现类
写一个配置类吧
package com.bo.partner.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
/**
* @author: bo
* @date: 2022/9/13
* @description:
*/
@Configuration
public class RedisTemplateConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(RedisSerializer.string());
return redisTemplate;
}
}
再改回用redisTemplate
运行成功
redisTemplate默认用了Lettuce
点进去
Jedis
独立于spring操作redis
Lettuce
高阶的操作redis的客户端
异步、连接池
连接池
复用连接
Redisson
分布式操作redis的java客户端
让你像在本地使用集合一样操作redis
分布式数据网格
使用场景
- 如果你用的是 Spring,并且没有过多的定制化要求,可以用 Spring Data Redis,最方便
- 如果你用的不是 Spring,并且追求简单,并且没有过高的性能要求,可以用 Jedis + Jedis Pool
- 如果你的项目不是 Spring,并且追求高性能、高定制化,可以用 Lettuce,支持异步、连接池
- 如果你的项目是分布式的,需要用到一些分布式的特性(比如分布式锁、分布式集合),推荐用 redisson
设计缓存 key
不同用户看到的数据不同
systemId:moduleId:func:options(不要和别人冲突)光userid容易冲突
partner:user:recommed:userId
redis 内存不能无限增加,一定要设置过期时间!!!
User loginUser = userService.getLoginUser(request);
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
String redisKey = String.format("partner:user:recommed:userId",loginUser.getId());
//如果有缓存。查缓存
Page<User> page = (Page<User>) valueOperations.get(redisKey);
if (page != null) {
return ResultUtils.success(page);
}
//没缓存继续查数据库
//不登录也推荐,但是不个性化,每个人一样
//登录之后就个性化推荐
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
page = userService.page(new Page<>(pageNum,pageSize), queryWrapper);
//写缓存
try {
valueOperations.set(redisKey,page);
} catch (Exception e) {
log.error("redis set key error", e);
}
}
不能用户每天看到的一样推荐
设置下过期时间
测试一下
10s过期
删除下之前的key
重新发请求
10s之后就没了
更多推荐
所有评论(0)