Day3学习笔记
定时任务/数据预热时间
问题:第一个用户访问还是很慢(加入第一个老板),也能一定程度上保护数据库
缓存预热的优点:
- 解决上面的问题,可以让用户始终访问很快
缺点:
- 增加开发成本(你要额外的开发、设计)
- 预热的时机和时间如果错了,有可能你缓存的数据不对或者太老
- 需要占用额外空间
怎么缓存预热?
- 定时
- 模拟触发(手动触发)
实现
用定时任务,每天刷新所有用户的推荐列表
注意点:
- 缓存预热的意义(新增少、总用户多)
- 缓存的空间不能太大,要预留给其他缓存空间
- 缓存数据的周期(此处每天一次)
定时任务实现
- Spring Scheduler(spring boot 默认整合了)
- Quartz(独立于 Spring 存在的定时任务框架)
- XXL-Job 之类的分布式任务调度平台(界面 + sdk)
第一种方式:
- 主类开启 @EnableScheduling
- 给要定时执行的方法添加 @Scheduling 注解,指定 cron 表达式或者执行频率
不要去背 cron 表达式!!!!!
并发问题
- 用户插入单元测试,注意打包时要删掉或忽略,不然打一次包就插入一次
- for 循环插入数据的问题:
- 建立和释放数据库链接(批量查询解决)
- for 循环是绝对线性的(并发)
private ExecutorService executorService = new ThreadPoolExecutor(
16, // 核心线程数 (corePoolSize)
1000, // 最大线程数 (maximumPoolSize)
10000, // 线程空闲时间 (keepAliveTime)
TimeUnit.MINUTES, // 时间单位 (unit)
new ArrayBlockingQueue<>(10000) // 任务队列 (workQueue)
);
任务队列 (workQueue)
- 值:
new ArrayBlockingQueue<>(10000)
- 作用:这是一个有界队列,用来存储等待执行的任务。
ArrayBlockingQueue
是一个基于数组的阻塞队列,具有固定的容量(这里是10000)。当线程池中的线程都在忙碌时,新提交的任务会被放入这个队列中等待处理。
- 超出队列容量:如果任务队列满了,而此时仍有新任务提交,线程池会创建新的线程来处理这些任务,但不会超过最大线程数(1000个)。
- 线程回收:一旦某个线程完成其工作并且空闲了超过指定的
keepAliveTime
(10000分钟),它将被终止,前提是当前线程数大于核心线程数。
二者配合使用完成并发操作
查询效率问题
-
数据库慢?预先把数据查出来,放到一个更快读取的地方,不用再查数据库了。(缓存)
-
预加载缓存,定时更新缓存。(定时任务)
-
多个机器都要执行任务么?(分布式锁:控制同一时间只有一台机器去执行定时任务,其他机器不用重复执行)
分布式
- 如果你用的是 Spring,并且没有过多的定制化要求,可以用 Spring Data Redis,最方便
- 如果你用的不是 SPring,并且追求简单,并且没有过高的性能要求,可以用 Jedis + Jedis Pool
- 如果你的项目不是 Spring,并且追求高性能、高定制化,可以用 Lettuce,支持异步、连接池
- 如果你的项目是分布式的,需要用到一些分布式的特性(比如分布式锁、分布式集合),推荐用 redisson
Redis
NoSQL 数据库
key - value 存储系统(区别于 MySQL,他存储的是键值对)
Redis 数据结构
-
String 字符串类型: name: "yupi"
-
List 列表:names: ["yupi", "dogyupi", "yupi"]
-
Set 集合:names: ["yupi", "dogyupi"](值不能重复)
-
Hash 哈希:nameAge:
-
Zset 集合:names: { yupi - 9, dogyupi - 12 }(适合做排行榜)
而redis一般要写个配置类才能用
/**
*
* 自定义序列化
*
*/
@Configuration
public class RedisTemplateConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
//创建RedisTemplate对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//设置连接工厂
redisTemplate.setConnectionFactory(connectionFactory);
//设置Key的序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
//创建Json序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//设置Value的序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
return redisTemplate;
}
}
redis 内存不能无限增加,一定要设置过期时间!!!
//无缓存,查数据库
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
userPage = userService.page(new Page<>(pageNum,pageSize),queryWrapper);
//写缓存,10s过期
try {
valueOperations.set(redisKey,userPage,30000, TimeUnit.MILLISECONDS);//存储到redis中并规定30000ms过期
} catch (Exception e){
log.error("redis set key error",e);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY