天机学堂项目总结(day3~day4)

目录

[Day03-02. 产品原型 - 分析业务流程](#Day03-02. 产品原型 - 分析业务流程)

[Day03-03. 产品原型.设计提交学习记录接口](#Day03-03. 产品原型.设计提交学习记录接口)

[Day03-04. 产品原型 - 设计查询学习记录接口](#Day03-04. 产品原型 - 设计查询学习记录接口)

[Day03-05. 产品原型 - 设计学习计划相关接口](#Day03-05. 产品原型 - 设计学习计划相关接口)

[Day03-06. 产品原型 - 设计数据库表结构](#Day03-06. 产品原型 - 设计数据库表结构)

[Day03-07. 开发接口 - 查询指定课程学习记录](#Day03-07. 开发接口 - 查询指定课程学习记录)

[Day03-08. 开发接口 - 提交学习记录的流程分析](#Day03-08. 开发接口 - 提交学习记录的流程分析)

[Day03-09. 开发接口 - 实现添加学习记录接口](#Day03-09. 开发接口 - 实现添加学习记录接口)

[问题:@Documented 这个注解有什么用 ?](#问题:@Documented 这个注解有什么用 ?)

问题:下图定义的自定义枚举是怎么实现功能的?

[Day03-10. 开发接口 - 测试提交学习记录接口](#Day03-10. 开发接口 - 测试提交学习记录接口)

[Day03-11. 开发接口 - 创建学习计划](#Day03-11. 开发接口 - 创建学习计划)

问题:下图注解作用?

[Day03-12. 开发接口 - 查询学习计划 - 分析代码流程](#Day03-12. 开发接口 - 查询学习计划 - 分析代码流程)

[Day03-13. 开发接口 - 查询我的学习计划 - 本周总的...](#Day03-13. 开发接口 - 查询我的学习计划 - 本周总的...)

问题:getBaseMapper()是什么?

问题:变成map的好处?

问题:SQL语句中sum和count区别?

[Day03-14 - 开发接口 - 查询我的学习计划 - 分页数据查询](#Day03-14 - 开发接口 - 查询我的学习计划 - 分页数据查询)

问题:需要sql查询返回是一个集合该怎么办?

[Day03-15. 开发接口 - 测试我的学习计划接口](#Day03-15. 开发接口 - 测试我的学习计划接口)

[Day04-01. 今日课程介绍](#Day04-01. 今日课程介绍)

[Day04-02. 方案分析 - 高并发优化方案分析](#Day04-02. 方案分析 - 高并发优化方案分析)

[Day04-03. 方案分析 - 播放进度统计优化方案](#Day04-03. 方案分析 - 播放进度统计优化方案)

问题:播放进度优化核心是哪里?

[Day04-04. 方案分析 - 播放进度统计数据持久化方案](#Day04-04. 方案分析 - 播放进度统计数据持久化方案)

[Day04-05. 方案分析 - 延迟任务](#Day04-05. 方案分析 - 延迟任务)

问题:解释Durationh个System.nanoTime()?

问题:idea生成单元测试的快捷键?

[Day04-06. 代码改造 - 添加播放记录到缓存并添加延迟任务](#Day04-06. 代码改造 - 添加播放记录到缓存并添加延迟任务)

[Day04-07. 代码改造 - 播放记录缓存的读取和清除方法](#Day04-07. 代码改造 - 播放记录缓存的读取和清除方法)

[Day04-08. 代码改造 - 异步执行延迟任务](#Day04-08. 代码改造 - 异步执行延迟任务)

问题:下图为什么要设置为null?

问题:Spring的生命周期?

[Day04-09. 代码改造 - 改造提交学习记录接口](#Day04-09. 代码改造 - 改造提交学习记录接口)

[Day04-10. 代码改造 - 测试提交学习记录接口](#Day04-10. 代码改造 - 测试提交学习记录接口)

[Day04-11. 课后思考题](#Day04-11. 课后思考题)

[问题:DelayQueue >存在的问题以及怎么优化?](#问题:DelayQueue >存在的问题以及怎么优化?)

问题:线程池怎么定义及使用?

[问题:线程池 7 大核心参数?](#问题:线程池 7 大核心参数?)


Day03-02. 产品原型 - 分析业务流程

Day03-03. 产品原型.设计提交学习记录接口

Day03-04. 产品原型 - 设计查询学习记录接口

Day03-05. 产品原型 - 设计学习计划相关接口

Day03-06. 产品原型 - 设计数据库表结构

Day03-07. 开发接口 - 查询指定课程学习记录

Day03-08. 开发接口 - 提交学习记录的流程分析

Day03-09. 开发接口 - 实现添加学习记录接口

问题:@Documented 这个注解有什么用 ?

让这个自定义注解,在生成 JavaDoc 文档时被显示出来。


具体说

  1. 它是 Java 原生的元注解(标记注解的注解)

  2. 不加 @Documented 别人用 IDEA 查看你的 @EnumValid 时,鼠标悬停、JavaDoc 里看不到这个注解

  3. 加上 @Documented 生成文档、鼠标悬浮提示时,@EnumValid完整显示在文档里


举个例子

你写了:

java

运行

复制代码
@Documented
public @interface EnumValid {
}

别人在使用时:

java

运行

复制代码
@EnumValid
private Integer status;

在 IDEA 鼠标悬浮、或生成 JavaDoc 时,就能看到 @EnumValid 这个注解,而不是被忽略。

问题:下图定义的自定义枚举是怎么实现功能的?

java 复制代码
/**
 * 用于状态的枚举校验
 **/
@Documented         // 生成JavaDoc时显示该注解
@Retention(RetentionPolicy.RUNTIME)  // 运行时生效
@Target({ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
// 可标注在:参数、字段、方法上
@Constraint(validatedBy = {EnumValidator.class, EnumValueValidator.class})
// 真正的校验逻辑由这两个类执行:
// EnumValidator 校验枚举
// EnumValueValidator 校验数字是否在指定列表里
public @interface EnumValid { // 定义注解

    // 校验失败时的提示信息
    String message() default "不满足业务条件";

    // 允许的数字列表,例如:enumeration = {0,1,2,3}
    int[] enumeration() default {};

    // 校验分组(固定格式)
    Class<?>[] groups() default { };

    // 负载(固定格式)
    Class<? extends Payload>[] payload() { };
}
  1. @Constraint(validatedBy = ...)
  • 绑定真正做校验的类

  • 这里绑定了两个:

    • EnumValidator:校验枚举

    • EnumValueValidator:校验数字是否在指定列表

Day03-10. 开发接口 - 测试提交学习记录接口

Day03-11. 开发接口 - 创建学习计划

问题:下图注解作用?

@Range表示范围

@Valid 的作用非常核心,简单一句话就是:

让 Spring 自动校验你的 DTO 参数(LearningPlanDTO)是否合法,不合法就直接返回错误,不需要你写 if 判断。

Day03-12. 开发接口 - 查询学习计划 - 分析代码流程

Day03-13. 开发接口 - 查询我的学习计划 - 本周总的...

问题:getBaseMapper()是什么?

getBaseMapper() = 获取当前 Service 对应的 Mapper 对象 就是用来调用 Mapper 里面的自定义方法的。

问题:变成map的好处?

Map<Long, Integer> countMap = IdAndNumDTO.toMap(list);

ListMap 的好处(背这个就够)

一句话:为了后面循环时,不用反复查库、不用反复遍历 List,直接 O (1) 快速取值!


详细解释(结合你这段代码)

你现在的代码:

java

运行

复制代码
// 1. 查询出来是 List 结构
List<IdAndNumDTO> list = recordMapper.countLearnedSections(userId, begin, end);

// 2. 转成 Map<id, 数量>
Map<Long, Integer> countMap = IdAndNumDTO.toMap(list);

后面你要循环每一个课程 ,拿对应已学习小节数

java

运行

复制代码
for (LearningLesson r : records) {
    // 从map里 1 步拿到值!
    vo.setWeekLearnedSections(countMap.getOrDefault(r.getId(), 0));

问题:SQL语句中sum和count区别?

  • SUM()对列的数值做加法运算,结果是「数值总和」
  • COUNT()统计行的数量,结果是「行数 / 非空值个数」
函数 作用 计算对象 空值处理
SUM(列名) 求和 :把指定列的数值累加起来 列中的数值 遇到 NULL 会自动忽略,不参与计算
COUNT(列名/*) 计数 :统计符合条件的行数 / 非空值数量 行 / 列的存在性 COUNT(列名) 忽略 NULLCOUNT(*) 统计所有行(含 NULL)

Day03-14 - 开发接口 - 查询我的学习计划 - 分页数据查询

问题:需要sql查询返回是一个集合该怎么办?

设置一个实体类接受它即可

Day03-15. 开发接口 - 测试我的学习计划接口

Day04-01. 今日课程介绍

Day04-02. 方案分析 - 高并发优化方案分析

Day04-03. 方案分析 - 播放进度统计优化方案

问题:播放进度优化核心是哪里?

要关注高频,那低频的就是第一次,因为它只有一次

Day04-04. 方案分析 - 播放进度统计数据持久化方案

Day04-05. 方案分析 - 延迟任务

问题:解释Durationh个System.nanoTime()?

java 复制代码
    public DelayTask(D data, Duration delayTime) {
        this.data = data;
        this.deadlineNanos = System.nanoTime() + delayTime.toNanos();
    }
  1. Duration 是什么?

一句话:Duration 是 Java 用来表示「一段时间」的工具类(时、分、秒、毫秒、纳秒)。

  1. System.nanoTime() 是什么?

一句话:获取系统当前的「纳秒级时间戳」,专门用来做精确计时、延迟、超时判断。

问题:idea生成单元测试的快捷键?

快速生成测试类

  1. 右键菜单 :在要生成测试类的类上右键,选择 Go To -> Test

  2. 快捷键 :使用 Ctrl + Shift + T 直接打开创建测试类的弹框。

Day04-06. 代码改造 - 添加播放记录到缓存并添加延迟任务

Day04-07. 代码改造 - 播放记录缓存的读取和清除方法

Day04-08. 代码改造 - 异步执行延迟任务

问题:下图为什么要设置为null?

  1. 先搞懂:MyBatis-Plus updateById 的默认行为

updateById只更新对象中「非空字段」 ,而忽略 null 值的字段。

问题:Spring的生命周期?

Spring Bean 生命周期

Bean 从创建到销毁的整个过程,一共分这几步,按顺序背就行:

  1. 实例化通过构造方法创建 Bean 实例(相当于 new 了一个对象)。

  2. 属性填充 进行依赖注入,给 Bean 里的 @Autowired@Value 等赋值。

  3. 执行 Aware 接口让 Bean 感知容器,比如:

    • BeanNameAware

    • BeanFactoryAware

    • ApplicationContextAware

  4. **前置处理(BeanPostProcessor#postProcessBeforeInitialization)**初始化之前的增强处理。

  5. 执行初始化方法

    1. @PostConstruct 标注的方法

    2. InitializingBean#afterPropertiesSet()

    3. XML 或注解指定的 initMethod

  6. **后置处理(BeanPostProcessor#postProcessAfterInitialization)**初始化之后的增强,AOP 代理就是在这里生成的。

  7. Bean 正常使用项目运行中被注入、被调用。

  8. 销毁容器关闭时执行:

    1. @PreDestroy

    2. DisposableBean#destroy()

    3. 指定的 destroyMethod


一句话精简版(面试口述)

Spring Bean 生命周期:实例化 → 属性注入 → Aware 感知 → 初始化前后置处理 → 初始化方法 → 正常使用 → 销毁。

Day04-09. 代码改造 - 改造提交学习记录接口

Day04-10. 代码改造 - 测试提交学习记录接口

Day04-11. 课后思考题

问题:DelayQueue<DelayTask<RecordTaskData>>存在的问题以及怎么优化?

目前我们的延迟任务执行还是单线程模式,大家将其改造为线程池模式,核心线程数与CPU核数一致即可。

问题:线程池怎么定义及使用?

① 先定义一个规范的线程池(带名字、带拒绝策略)

java 复制代码
private ThreadPoolExecutor poolExecutor;

// 静态内部类或直接定义线程工厂
private ThreadFactory threadFactory = new ThreadFactoryBuilder()
        .setNameFormat("delay-task-pool-%d")
        .build();

@PostConstruct
public void init() {
    // 1. 构造规范线程池
    poolExecutor = new ThreadPoolExecutor(
            12,
            12,
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),  // 队列放大一点
            threadFactory,                   // 命名线程工厂
            new ThreadPoolExecutor.CallerRunsPolicy()  // 更友好的拒绝策略
    );

    // 2. 用自己的线程池执行,而不是默认ForkJoinPool
    poolExecutor.execute(this::handleDelayTask);
}

② 加上优雅关闭

java 复制代码
@PreDestroy
public void destroy() {
    if (poolExecutor != null) {
        poolExecutor.shutdown();
        try {
            if (!poolExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                poolExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            poolExecutor.shutdownNow();
        }
    }
}

问题:线程池 7 大核心参数?

java 复制代码
ThreadPoolExecutor(
    int corePoolSize,      // 核心线程数(一直存活)
    int maximumPoolSize,   // 最大线程数(核心+非核心)
    long keepAliveTime,    // 非核心线程空闲多久被回收
    TimeUnit unit,         // 时间单位
    BlockingQueue<Runnable> workQueue,  // 任务队列
    ThreadFactory threadFactory,        // 线程工厂(给线程起名字)
    RejectedExecutionHandler handler    // 拒绝策略
)

本文摘要:课程内容主要围绕学习系统开发展开,重点讲解了产品原型设计、接口开发和性能优化。Day03课程详细介绍了学习记录和计划的接口设计、数据库表结构及实现过程,包括查询/提交学习记录接口开发,并讨论了自定义枚举校验的实现原理。Day04课程聚焦高并发优化方案,特别是播放进度统计的优化策略,涉及延迟任务处理、缓存机制和MyBatis-Plus的更新行为。文章还穿插讲解了Spring生命周期、SQL函数区别等关键技术点,为构建高效学习系统提供了完整的技术方案。

相关推荐
我叫Ycg2 小时前
C++ 中关于插入函数insert() 与 emplace() 的区别与使用建议
开发语言·c++
摇滚侠2 小时前
给我提供一个 sqlyog 下载地址
java
码农的神经元2 小时前
2026 MathorCup 选题建议:A/B/C/D/E 题到底怎么选?
c语言·开发语言·数学建模
Seven972 小时前
【从0到1构建一个ClaudeAgent】协作-团队协议
java
网域小星球2 小时前
C++ 从 0 入门(三)|类与对象基础(封装、构造 / 析构函数,面试必考)
开发语言·c++·面试·构造函数·析构函数
Dxy12393102162 小时前
Python如何去掉文本中的表情符号
开发语言·python
网域小星球2 小时前
C++ 从 0 入门(二)|引用与指针区别、函数重载、内联函数(面试高频)
开发语言·c++·面试·函数重载·内联函数·引用与指针区别
希望永不加班2 小时前
SpringBoot 中 AOP 实现接口限流
java·spring boot·后端·spring