单体架构、高可用集群、分布式架构、微服务
课程项目的大致发展是:单体架构
-> 高可用集群
-> 分布式架构
-> 微服务
。
其中就需要理解,单体架构、集群、分布式和微服务之间的区别了。
借用 知乎的热门回答,简单来讲就是 单体架构 可以看做一名厨师,当门店生意很好的时候,此时雇请多第二名厨师,而这位厨师和之前的厨师能做出一模一样的饭菜,此时就可以看做为一个 集群;而再后来生意更加好的时候,雇请了一些配菜员,他能干洗菜、切菜之类的工作,用来分担厨师的负担,此时厨师和配菜员的关系就是 分布式;如果工作再细分下去,比如这个配菜员只能洗菜,那个配菜员只能切菜,那么这就是 微服务 的概念了。
同时这里也区别一下 高并发 和 高吞吐 之间的概念区别。可以拿CPU举例,高吞吐 可以看做单核的处理能力,即一个请求发送到后端,此时系统数据量很大时,后端处理结果返回的响应速度。而 高并发 就像是多核的处理分配问题,一个网站积累的用户越多,对后端的请求量就会越来越大,此时后端应对这种情况下的响应速度。
项目的开端
项目的开始就是技术的选型,区分了 SpringBoot
和 SpringMVC
的区别,其实主要理解 SpringBoot
的核心设计思想就能明白二者的区别,它的核心设计思想就是:约定优于配置,它默认配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包,SpringBoot
整合了所有的框架,本质上开发人员只需规定应用中不符合约定的部分就可以了,而不是得像 SpringMVC
那样配置所有信息。例如 SpringBoot
约定 Controller
层就是 Web 请求层,这就可以省略了 MVC 的配置,约定了 以 Service 结尾 的类自动注入事务,这就可以省略 Spring 的切面事务配置等等。
在确认使用 SpringBoot 后就可以正式地学习教程了。
- 项目的开启初期就应该理顺数据表、创建好数据表,这里使用了
PDman
数据建模工具,详情可看 《PDMan笔记》,同时初始化项目的聚合工程,详情可看《SpringBoot 笔记(项目初始化)》; - 使用了自定义的 MyBatis 逆向生成工具,他可以帮助生成 Pojo、Dao、Mapper,并且生成的 Mapper 接口封装了常用的方法。
- 整合 Swagger2,Swagger 2是一个接口文档生成工具,使用它可以与前端对接时省事很多,同时它也能提供很好的测试接口功能;
- 整合日志,由于SpringBoot包含的日志包比较臃肿,这里在 pom 文件中使用右键选择
Diagrams
->show dependencies
i显示依赖汇总图,并把内置的spring-boot-starter-logging
给Exclude
剔除出去,并添加slf4j
日志依赖,同时编写log4j.properties
依赖配置文件,此时要注意的是日志的输出路径,如果是window系统时,不写具体的硬盘名称,会以项目所在的硬盘添加该设置的路径作为最终日志文件的存放路径; - 设置 Service 层切面,日志输出记录每个 Service 的耗时时间;
- 单元测试,直接配置在api层即可;
- 开发环境和生产环境时,
Application.yml
文件的配置; - 设置跨域
- 设置
spring-boot-devtools
热部署,《IntelliJ IDEA Spring boot devtools 实现热部署》,要注意
至此,项目的初始化就基本完成了。
完成单体项目下来需要记下来的点
1 用户模块
- 统一规范,VO,BO,pojo;
- 前后端的 cookies 交互;
@RequestBody
、@RequestParam
,@PathVariable
(首页根据分类Id 获取六个商品推荐的接口) 的区别;
2 首页模块
- Mapper封装了常用的方法中使用
example
实例的升降序查询(首页获取轮播图列表接口); - 自定义Mapper接口,返回的pojo类中还有数组属性的字段,该如何编写 XML 文件映射到自定义 VO 对象(根据父级Id 获取其下一级的所有子分类信息接口);
- sql 语句中的反单引号 ` 的作用;
3 商品模块
- sql语句根据表中某个字段的取值不同,从而查询该表对应条件时的汇总数量,使用
case
语法(根据商品主键获取评论数接口); @RequestParam
的required
属性为false
时,前端的传值方式(根据关键词获取商品列表接口);- 使用
PageHelper
分页插件(根据关键词获取商品列表接口); - MyBatis 的
<if>
标签;<choose>
标签;test
属性判断单个字符串时,如何告诉 Mybatis 该比较类型是String
,而不要和char
类型混淆;${}
和#{}
的区别(根据关键词获取商品列表接口); - 数组转化到集合的语法糖:
Collections.addAll(集合, 数组);
(根据规格id集合字符串获取最新商品信息接口); - MyBatis 的
<foreach>
标签(根据规格id集合字符串获取最新商品信息接口);
4 订单模块
- 购物车的存储信息方式:
- Cookie:
- 优点:性能好、访问快,没有与数据库交互
- 缺点1:更换电脑购物车数据会丢失
- 缺点2:电脑被其他人登录,隐私安全问题
- Session
- 优点:初期性能好。访问快
- 缺点1:Session 基于内存,用户量庞大影响服务器性能
- 缺点2:只能存在与当前会话,不适用集群与分布式系统
- 数据库
- 优点:数据持久化,可在任何地方任何时间访问
- 缺点:频繁读写数据库,造成数据库压力
- Redis 缓存
- 优点:数据持久化,可在任何地方任何时间访问
- 优点2:频繁读写只基于缓存,不会造成数据库压力
- 优点3:适用于集群与分布式,可扩展性强
- Cookie:
- 高并发导致扣库存问题,解决方式:
synchronized
修饰词:不推荐使用,集群下无用,性能低下- 锁数据库:不推荐,导致数据库性能低下
- 分布式锁:
zookeepper
,reids
- 适用乐观锁,什么是乐观锁,什么是悲观锁,什么是减少乐观锁的粒度,提高并发能力(创建订单接口)
- Service层抛出异常
RuntimeException
触发事务回滚(创建订单接口); - Mapper封装了常用的方法中使用 pojo 实例查询(根据用户id获取用户地址);
- 使用语法糖
BeanUtils.copyProperties(Object source, Object target);
实现不同类的对象之间相同属性的赋值(用户修改地址); - 付款超时时,要设置订单的交易状态为关闭,定时任务的创建:
- 使用
@schedule
注释开启定时任务,缺点:- 1、有时间差,即每条订单不一定会刚刚达到一天的时长后就马上关闭,程序不严谨
- 2、假如数据量大,全表查找全部未支付的订单对数据库造成性能负担
- 3、不支持集群,假设部署了多台服务器,定时任务就会多台执行,导致浪费,解决方案只使用一台服务器单独使用定时任务
- 所以
@schedule
只适用一些小型轻量级项目,传统项目
- 最好使用消息队列:
MQ
->RabbitMQ
,Kafka
等的延时任务
- 使用
- 使用
RestTemplate
向支付中心发起请求
5 用户中心模块
- 使用
hibernate
检查传入参数是否符合规格(更新用户消息接口); - 添加静态资源服务(获取头像图片);
- 将
properties
文件映射为 Bean 实例使用(上传用户头像接口); - 限制上传文件的大小,并且全局捕获异常(上传用户头像接口);
- 注意存放文件时,Window系统和Linux系统的路径区别(上传用户头像接口);
- 更新头像 url 到数据库,需要添加时间戳,以防浏览器缓存;
- MyBatis 插入一个列表的数据(用户评价商品接口);
- MyBatis 嵌套查询,避免 PageHelper 插件出错(获取用户的所有订单接口);
- Mapper封装了常用的方法中使用
updateByExampleSelective
,使exemple
和 pojo 联合更新操作(根据用户id获取用户地址);
6 项目发布
- linux 虚拟机如何联网,修改
/etc/sysconfig/network-scripts/ifcfg-ens33
文件的ONBOOT
为yes
,然后执行service network restart
刷新配置。 《NAT模式和桥接模式实现局域网其他物理机器与Vmware虚拟机互相访问》; - 使用
ifconfig
获取 IP 地址,端口为22
,连接 SecureCRT,FileZilla; - 设置防火墙,《Centos7 防火墙配置》;
- 打包 war 包:
- 1、设置 controller 层的
pom.xml
的打包类型为war
- 2、设置剔除 SpringBoot 内置 tomcat
- 3、设置 war 包启动类
- 1、设置 controller 层的