苍穹外卖Day07笔记

一、Redis 相关

1. redisTemplate.keys 方法

  • 功能 :RedisTemplate 提供的批量查询 Key 的方法,支持通配符匹配(* 匹配任意字符、? 匹配单个字符、[] 匹配指定范围)。
  • 语法Set<String> keys = redisTemplate.keys("pattern");(如 redisTemplate.keys("user:*") 匹配所有以 user: 开头的 Key)。
  • 使用注意
    • 底层执行 Redis 的 KEYS 命令,在 Redis 存储海量 Key 时,会阻塞主线程(Redis 单线程),生产环境禁止高频使用
    • 替代方案:使用 Redis 有序集合(ZSet)或哈希(Hash)归类存储,避免全量扫描 Key。

2. Redis 树形数据实现

Redis 本身无原生树形结构,需通过 Key 设计/数据结构模拟:

  • 方案1:Key 层级命名 :用 : 分隔层级,如 category:1:sub:2(表示分类1下的子分类2),结合 keys("category:1:*") 查询子节点;
  • 方案2:Hash 存储节点关系hset("tree:category", "1", "子节点ID列表")hget("tree:category", "1") 获取子节点;
  • 方案3:ZSet 排序层级 :为每个节点设置分数(层级深度),zadd("tree:category", 1, "节点1")zrange("tree:category", 0, -1) 按层级排序。

二、Spring 核心特性

1. 静态方法无法访问 Spring 注入的非静态成员

  • 核心原因
    • 静态方法属于「类级别」,类加载时即初始化,优先级高于 Spring 容器;
    • Spring 注入的成员(如 @Autowired 标注的对象)属于「实例级别」,需等 Spring 初始化 Bean 后才存在;
    • 静态方法执行时,Bean 尚未注入,直接访问会抛出 NullPointerException
  • 解决方案
    • 避免在静态方法中依赖 Spring 注入的 Bean;
    • 通过 Spring 上下文工具类获取 Bean(ApplicationContext.getBean(Class));
    • 将静态方法改为实例方法,配合 @Component 让类被 Spring 管理。

2. Spring Cache 缓存框架

(1)基础信息
  • 归属 :Spring 框架原生功能(隶属于 org.springframework.cache 包),无需额外第三方框架核心依赖;
  • 核心作用:通过注解简化缓存逻辑,无需手动调用 RedisTemplate 等缓存客户端。
(2)支持的缓存介质

Spring Cache 是「缓存抽象层」,可对接多种底层缓存实现:

缓存类型 适用场景
Redis 分布式系统、生产环境(最常用)
Caffeine 单机应用、本地缓存(性能最优)
Ehcache 传统企业级应用
ConcurrentHashMap 测试环境、简单单机场景
  • 数据库兼容性:可配合任意数据库(MySQL/Oracle/PostgreSQL 等),仅负责缓存业务查询结果,与底层存储数据库无关。
(3)核心注解及 SpEL 表达式
注解 核心作用 关键参数 & SpEL 示例
@EnableCaching 开启 Spring Cache 功能(加在启动类/配置类)
@Cacheable 查询缓存:有缓存直接返回,无则执行方法并缓存结果 cacheNames="userCache"(缓存块名称) key="#user.id"(取入参user对象的id) key="#p0.id"/#a0.id(取第0个入参的id) key="#result.id"(取方法返回值的id)
@CachePut 更新缓存:强制执行方法,将结果更新到缓存(用于新增/修改) key="#id"(指定缓存Key)
@CacheEvict 删除缓存:移除指定Key或清空缓存块 key="#id"(删除指定Key) allEntries=true(清空当前cacheNames下所有缓存)
  • SpEL 与 @RequestBody 配合 :前端传递 JSON 数据时,@RequestBody UserDTO userDTO 可直接用 key="#userDTO.id" 取参。
(4)@Cacheable 与 @CachePut 核心区别
维度 @Cacheable @CachePut
方法执行逻辑 缓存命中则不执行方法,直接返回缓存值;未命中才执行方法 必须执行方法,执行后将结果覆盖到缓存
适用场景 查询操作(如根据ID查用户、查菜品列表) 新增/全量更新操作(如新增用户、修改菜品信息)
缓存写入时机 方法执行后(未命中时) 方法执行后(强制写入)
(5)代理方法原理

Spring Cache/事务/AOP 底层均基于「动态代理」实现:

  • 核心逻辑 :当调用标注了 @Cacheable/@Transactional 的方法时,实际执行的是 Spring 生成的「代理类方法」,而非原方法;
  • 执行流程:代理类先拦截请求 → 执行缓存判断/事务开启等逻辑 → 再调用原方法 → 最后执行缓存写入/事务提交等逻辑;
  • 注意点:同类内调用标注注解的方法,代理不会生效(未走代理类),需通过注入的 Bean 调用。

3. 缓存数据读取流程(用户视角)

用户手机/前端无 Redis 数据库,缓存仅存在于服务器端,完整流程:

  1. 用户通过前端(APP/网页)发起 HTTP 请求 → 后端服务器;
  2. 后端接口先查询 Redis 缓存:
    • 缓存命中:直接将缓存数据转为 JSON 格式;
    • 缓存未命中:查询 MySQL 数据库,将结果写入 Redis 后再转 JSON;
  3. 后端将 JSON 数据通过 HTTP 响应返回给前端;
  4. 前端解析 JSON 并展示给用户。

4. @RestController 注解

  • 核心作用 :标记类为 SpringMVC 控制器,且所有方法返回值自动转为 JSON 响应(无需手动加 @ResponseBody);

  • 底层构成@RestController = @Controller + @ResponseBody

  • 参数说明:该注解无入参,仅作为「标识注解」,告知 Spring 此类用于处理 HTTP 请求并返回 JSON 数据;

  • 示例

    java 复制代码
    @RestController
    @RequestMapping("/user")
    public class UserController {
        @GetMapping("/{id}")
        public Result<UserDTO> getUserById(@PathVariable Long id) {
            // 返回值 Result<UserDTO> 自动转为 JSON 响应
            return Result.success(userService.getById(id));
        }
    }

5. 接口设计:@Service 与接口的关系

(1)@Service 标注位置
  • @Service 必须标注在实现类 上,而非接口:
    • 接口无法实例化,Spring 只能创建实现类的 Bean 并纳入容器管理;
    • 接口仅定义方法规范,无具体实现逻辑,无法被 Spring 管理。
(2)控制层注入接口类型的原因(面向接口编程)
  • 核心意义

    1. 解耦 :控制层仅依赖接口规范,不依赖具体实现,更换实现类(如 UserServiceImplV2)时,控制层无需修改代码;
    2. 易测试:单元测试时可通过 Mock 框架模拟接口实现,无需依赖真实业务逻辑;
    3. 符合开闭原则:扩展新功能只需新增实现类,无需修改原有代码;
    4. AOP 兼容:Spring 动态代理默认基于接口生成代理类,更稳定。
  • 示例

    java 复制代码
    // 接口:定义规范
    public interface UserService {
        UserDTO getById(Long id);
    }
    
    // 实现类:加@Service,被Spring管理
    @Service
    public class UserServiceImpl implements UserService {
        @Override
        public UserDTO getById(Long id) {
            // 具体实现
        }
    }
    
    // 控制层:注入接口类型
    @RestController
    public class UserController {
        @Autowired
        private UserService userService; // 实际注入的是UserServiceImpl的Bean
    }

6. Mapper 接口的设计逻辑

MyBatis 中 Mapper 仅定义接口,无需编写实现类:

  • 核心原理:MyBatis 启动时,通过「动态代理」为 Mapper 接口生成代理实现类;
  • 代理类作用:解析 Mapper 接口方法与 XML/注解中的 SQL,自动生成 JDBC 执行逻辑(如参数绑定、结果集映射);
  • 优势:开发者只需定义方法名和 SQL,无需编写重复的 JDBC 代码,简化数据库操作。

三、AOP 面向切面编程

1. 切面(AOP)核心定义

  • 本质:将与业务无关但需全局统一执行的逻辑(如日志、权限、事务),从业务代码中抽离出来,通过「切面」统一管理,实现「横切逻辑」与业务逻辑解耦;
  • 通俗理解:在不修改原有业务代码的前提下,为方法添加「增强功能」(如执行方法前校验权限、执行后记录日志)。

2. 常用 AOP 场景

场景 作用
全局日志记录 记录接口请求参数、响应结果、执行耗时
权限校验 方法执行前校验用户是否有操作权限
公共字段自动填充 如 @AutoFill 注解,为实体类自动填充 createTime、updateUser 等字段
事务管理 方法执行前开启事务,执行后提交/回滚
缓存处理 配合 Spring Cache 实现缓存逻辑
异常统一处理 捕获方法抛出的异常,返回标准化响应
接口限流 限制接口的请求频率,防止过载

四、数据库设计

1. 冗余字段

  • 定义 :在数据表中存储可通过关联查询获取的字段(如订单表中存储 username,而该字段原本属于用户表);
  • 核心作用
    1. 提升查询性能:避免多表联查,直接从当前表获取数据(如查询订单列表时,无需关联用户表即可显示用户名);
    2. 简化业务逻辑:统计报表、导出数据时,无需复杂联表,降低代码复杂度;
    3. 数据溯源:即使关联表数据修改(如用户名修改),冗余字段仍能保留历史状态(如订单创建时的用户名)。
  • 缺点:增加数据存储成本,需保证冗余字段与源字段的一致性(如通过触发器/代码同步)。

五、项目构建与接口调试

1. Gradle 构建工具

  • 核心作用:与 Maven 功能一致,用于 Java 项目的构建、依赖管理、打包部署;
  • 优势
    • 语法简洁(基于 Groovy/Kotlin),配置文件比 Maven 更轻量化;
    • 构建速度更快,支持增量构建;
    • 兼容性强,可与 Maven 仓库互通;
  • 核心功能
    1. 管理项目依赖(自动下载 jar 包);
    2. 编译源代码、运行单元测试;
    3. 打包项目(生成 jar/war 包);
    4. 部署项目到服务器。

2. Swagger 接口工具

  • 核心定位:API 文档生成 + 在线接口调试工具;
  • 核心价值
    1. 自动生成文档 :通过 @Api/@ApiOperation 等注解,自动生成规范化的接口文档,无需手动编写;
    2. 在线调试:后端开发者/前端开发者可直接在网页上填写参数、发送请求、查看响应,无需依赖 Postman 等第三方工具;
    3. 接口规范统一:前后端基于同一套文档对接,减少沟通歧义。

3. 前端发送 JSON 数据的方式

JSON 数据不藏在 URL 中,核心传输方式:

  • 请求体(Request Body)

    • 适用请求方式:POST/PUT/PATCH(GET 无请求体);

    • 请求头必须设置:Content-Type: application/json

    • 示例(前端 Axios 代码):

      javascript 复制代码
      axios.post('/user/save', {
          name: '张三',
          age: 20
      }, {
          headers: {
              'Content-Type': 'application/json'
          }
      });
  • URL 传参:仅用于传递简单参数(如 ID、页码),JSON 数据因体积/格式问题,不适合 URL 传输(URL 有长度限制且需编码)。

相关推荐
左左右右左右摇晃2 小时前
String、StringBuffer、StringBuilder的区别
java·笔记
蒸蒸yyyyzwd2 小时前
30天学习笔记day1
笔记
罗罗攀2 小时前
PyTorch学习笔记|张量的线性代数运算
人工智能·pytorch·笔记·学习·线性代数
sin°θ_陈2 小时前
行业调研——XGRIDS (其域创新):空间数据生产、资产化与工业工作流的真正价值
经验分享·笔记·深度学习·3d·金融·3dgs·空间智能
苦涩花开54862 小时前
Kubernetes学习,记一些笔记
笔记·学习·kubernetes
丝斯20112 小时前
AI学习笔记整理(74)——Python学习3
笔记·python·学习
宵时待雨3 小时前
C++笔记归纳13:map & set
开发语言·数据结构·c++·笔记·算法
1104.北光c°4 小时前
滑动窗口HotKey探测机制:让你的缓存TTL更智能
java·开发语言·笔记·程序人生·算法·滑动窗口·hotkey
左左右右左右摇晃13 小时前
计算机网络笔记整理
笔记·计算机网络