外卖项目总结(3)

外卖项目总结(3)

技术点

  1. Redis非关系型数据库
    基于内存的key-value结构数据库。读写性能高,常用于存储短时间大量访问的热点数据。
    而MySQL则是基于磁盘的二维表结构的数据库
  • 应用场景:缓存,消息队列,排行榜、分布式锁……
  • Java中Redis的使用:1. 导入坐标 2. 配置Redis数据源(host、port、password、DB序号)3. 编写配置类,创建Redis Template对象 4. 调用Redis Template对象操作Redis
  • 常用命令总结:

Redis命令总结

  • 注意事项:
    配置文件中设置密码,Redis数据库没有用户的概念,只有密码。
    Redis中不同的数据库中数据隔离
    Java中的String不等于Redis中的String,Spring Data Redis 将java对象序列化为Redis中的String再存储,所以设置序列化器正确显示key。

  • 实际应用:缓存菜品
    问题:菜品数据存在数据库中,短时间大量用户访问会导致数据库过载(图片加载不出来)
    解决:利用Redis将数据存储在缓存中
    通过Redis缓存菜品,减少DB查询:当前端发起查询菜品请求时,在后端先查看缓存是否存在,如果存在直接读取,否则查询DB,再读取并载入缓存。
    问题:数据不一致:DB中数据被修改了,但是缓存中的数据没变
    解决:数据库数据变动:清理缓存,引出了Spring Cache
    应用效果:菜品查询速度从46ms降低到9ms。

  • redis序列化方式
    JdkSerializationRedisSerializer:默认,它使用 Java 的序列化机制将 Java 对象序列化为字节数组
    StringRedisSerializer:默认,使用 String 类型作为 Redis 的 Key 和 value 的序列化方式,它可以将 Java 对象转换为字符串,也可以将字符串转换回 Java 对象。
    GenericToStringSerializer :可以将任何对象泛化为字符串并序列化
    Jackson2JsonRedisSerializer :一种更加轻量级的序列化方式,它仅仅支持JSON格式的序列化和反序列化
    GenericJackson2JsonRedisSerializer:使用Jackson库将Java对象序列化为JSON格式的字符串,以便在Redis中存储和检索 — 常用

  1. Spring Cache
    基于注解的缓存功能,简化开发。基于代理技术实现的,抽象接口,其实现有:Redis、Caffeine、EHCache
  • 应用场景:缓存数据,防止重复请求,实现分布式系统中的数据共享。
  • 使用:1. 引入依赖 2.导入Redis Java 客户端,告诉Spring Cache用哪个实现
  • 常用注解:

@EnableCaching :开启缓存注解功能:加在启动类上。
@Cacheable(cacheName = “”,key = “spel表达式”):加在方法上,方法执行前查询缓存数据,有则取,无则放。
@CachePut(value = “”,key = “spel表达式”):加在方法上,先执行方法,将方法返回值放入缓存(只放)
@CacheEvict(cacheNames = “”,key = “spel”):删除缓存

  • tips:在设计数据库时,通常设计额外的冗余字段提高查询速度,减少多表联查,但是冗余字段通常满足不易更改的条件。
  1. HttpClient
    用于服务器端(Java端)发送Http请求
  • 发送请求步骤:

创建HttpClient对象
创建Http请求对象(Get or Put),并指定请求URL
调用HttpClient的execute方法发送请求
释放连接

  1. Spring Task - 任务调度工具
    Spring框架提供的任务调度工具,按照约定自动执行某个代码逻辑
  • 应用场景:信用卡每月还款提醒,银行贷款每月还款提醒,入职纪念日发送通知
  • 使用:1. 导入 Spring-context 坐标 2. 开启任务调度@EnableScheduling 3. 自定义定时任务类(交给IOC容器管理) 4 .@Scheduled(cron表达式)在方法上添加
  • cron表达式:定义任务触发时间
    构成规则:6~7个域,空格分隔,每个域的含义:秒 分 时 日 月 周 年
    eg:2022年10月21日上午九点整:0 0 9 21 10 ?2022(注意周和日不能同时出现)
  1. WebSocket
    基于TCP连接的全双工通信网络协议。实现浏览器与服务器全双工通信——依次握手,就可以创建持久性的连接,并且进行双向数据传输。
    WebSocket是双向的长连接,类似于电话通话;http是请求相应模式,短连接,更像是发电报。
    WebSocket底层是通过TCP连接的。
  • 应用场景:视频弹幕、网页聊天、体育实况更新、股票基金
  • 服务器端实现步骤:

5.1 WebSocket.html 页面作用
5.2 导入坐标
5.3 定义组件WebSocketServer(与Controller类似)(交给IPC容器管理)
5.4 导入配置类WebSocketConfiguration
5.5 导入定时任务类,定时向客户端推送数据

  • 关键注解:Map<String, Session> (存放会话对象)
    @ServerEndpoint(“url”):类似requestMapping
    @OnOpen:建立连接成功调用的方法
    @OnMessage:收到Client后调用的方法
    @OnClose:连接关闭调用的方法
  1. 阿里云OSS
    云存储服务,存储文本、图片、视频
  • 应用场景:上次文件
  • 使用

6.1 导入依赖
6.2 引入工具类Utils
6.3 编写配置类config,属性实体类properties
6.4 在配置文件yam中设置endpoint、accessKeyId、accessKeySecret、buckeName
6.5 编写文件上传代码逻辑

  1. 事务处理Transactional
    一组原子性的操作序列,这些操作要么全部执行,要么全部不执行
  • 特性:原子性、一致性、隔离性、持久性
  • 应用场景:当一组操作需要同时执行。
  • 使用:
    启动类上加上@EnableTransactionManagement注解开启注解方式的事务管理
    在需要事务管理的方法上加上注解:@Transactional()
    rollbackFor属性:回滚指定类型的异常:@@Transactional(rollbackFor = Exception.class)
    propagation属性:
    • 事务传播:当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制?
    • REQUIRED:默认值,需要事务,有则加入,无则创建新事务
    • REQUIRED_NEW:总是创建新事务
  1. Apache Echarts
    一个基于 JavaScript 的数据驱动的开源可视化图表库

  2. Apache POI
    操作Excel文件,导出、读取Excel

  • 使用:
  1. 导入依赖
  2. 新建文件对象 new XSSWorkbook()
  3. 创建Sheet页:excel.createSheet("")
  4. 创建行sheet.createRow(0)//0为第一行
  5. 创建单元格 row.createCell(0)//row行第一格
  6. 赋值 setCellValue
  7. 写出磁盘,关流

10 . @ConfigurationProperties
注入外部配置的属性

  • 注解
    @EnableConfigurationProperties开启配置
    @Value注解只能一个一个的进行外部属性的注入。
    @ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中,且能注入数组结构
  • 使用:使用在类上,eg: @ConfigurationProperties(prefix = “yam文件对应的路径”)
  1. MySQL嵌套查询

  2. 验证码
    利用Hutool工具生成验证码,并保存验证码至数据库,方便验证

  3. Debug

  • OSS依赖版本
    NoSuchFileError:类的定义在编译时和运行时不一致导致的
    解决方法:mvn dependency:tree命令,找出库中旧版本依赖
    问题出现原因:我在dependency management 中指定了新版本OSS,但是子模块中的旧版本没有删除,导致加载了旧版本的类,却使用了新版本的字段。
    注意:如果没有依赖管理,maven会根据最短路径来控制版本。

OSS debug

  • Mybatis
    问题描述:每个map有两个不同类型的键值对:
    key-number、key-name
    定义时指定了Map<String, Integer> 类型错误,但是输出依然正确

Mybatis Debug

why?

  1. 因为实际返回的是Map<String, Object>,数据库中name时String,number时Integer,Mybatis会默认将查询封装为Object
  2. 定义的是Map<String, Integer>,但是后续没有对name的值做Integer相关操作,所以没有报错。

注意:泛型只是编译检查,运行时泛型会被擦除,JVM只看得到Map

  • 流操作

流操作bug

.map()后没有调用终止操作,所以流中的操作不会执行

posted @ 2025-07-10 21:54  waterme  阅读(15)  评论(0)    收藏  举报