外卖项目总结(3)
外卖项目总结(3)
技术点
- Redis非关系型数据库
基于内存的key-value结构数据库。读写性能高,常用于存储短时间大量访问的热点数据。
而MySQL则是基于磁盘的二维表结构的数据库
- 应用场景:缓存,消息队列,排行榜、分布式锁……
- Java中Redis的使用:1. 导入坐标 2. 配置Redis数据源(host、port、password、DB序号)3. 编写配置类,创建Redis Template对象 4. 调用Redis Template对象操作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中存储和检索 — 常用
- 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:在设计数据库时,通常设计额外的冗余字段提高查询速度,减少多表联查,但是冗余字段通常满足不易更改的条件。
- HttpClient
用于服务器端(Java端)发送Http请求
- 发送请求步骤:
创建HttpClient对象
创建Http请求对象(Get or Put),并指定请求URL
调用HttpClient的execute方法发送请求
释放连接
- 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(注意周和日不能同时出现)
- 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:连接关闭调用的方法
- 阿里云OSS
云存储服务,存储文本、图片、视频
- 应用场景:上次文件
- 使用
6.1 导入依赖
6.2 引入工具类Utils
6.3 编写配置类config,属性实体类properties
6.4 在配置文件yam中设置endpoint、accessKeyId、accessKeySecret、buckeName
6.5 编写文件上传代码逻辑
- 事务处理Transactional
一组原子性的操作序列,这些操作要么全部执行,要么全部不执行
- 特性:原子性、一致性、隔离性、持久性
- 应用场景:当一组操作需要同时执行。
- 使用:
启动类上加上@EnableTransactionManagement注解开启注解方式的事务管理
在需要事务管理的方法上加上注解:@Transactional()
rollbackFor属性:回滚指定类型的异常:@@Transactional(rollbackFor = Exception.class)
propagation属性:- 事务传播:当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制?
- REQUIRED:默认值,需要事务,有则加入,无则创建新事务
- REQUIRED_NEW:总是创建新事务
-
Apache Echarts
一个基于 JavaScript 的数据驱动的开源可视化图表库 -
Apache POI
操作Excel文件,导出、读取Excel
- 使用:
- 导入依赖
- 新建文件对象
new XSSWorkbook()
- 创建Sheet页:
excel.createSheet("")
- 创建行
sheet.createRow(0)//0为第一行
- 创建单元格
row.createCell(0)//row行第一格
- 赋值
setCellValue
- 写出磁盘,关流
10 . @ConfigurationProperties
注入外部配置的属性
- 注解
@EnableConfigurationProperties开启配置
@Value注解只能一个一个的进行外部属性的注入。
@ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中,且能注入数组结构 - 使用:使用在类上,eg: @ConfigurationProperties(prefix = “yam文件对应的路径”)
-
MySQL嵌套查询
-
验证码
利用Hutool工具生成验证码,并保存验证码至数据库,方便验证 -
Debug
- OSS依赖版本
NoSuchFileError:类的定义在编译时和运行时不一致导致的
解决方法:mvn dependency:tree
命令,找出库中旧版本依赖
问题出现原因:我在dependency management 中指定了新版本OSS,但是子模块中的旧版本没有删除,导致加载了旧版本的类,却使用了新版本的字段。
注意:如果没有依赖管理,maven会根据最短路径来控制版本。
- Mybatis
问题描述:每个map有两个不同类型的键值对:
key-number、key-name
定义时指定了Map<String, Integer> 类型错误,但是输出依然正确
why?
- 因为实际返回的是Map<String, Object>,数据库中name时String,number时Integer,Mybatis会默认将查询封装为Object
- 定义的是Map<String, Integer>,但是后续没有对name的值做Integer相关操作,所以没有报错。
注意:泛型只是编译检查,运行时泛型会被擦除,JVM只看得到Map
- 流操作
.map()后没有调用终止操作,所以流中的操作不会执行