12、基本的车票预定功能开发
12-1 本章介绍 (04:28)

12-2 增加余票信息表以提高余票查询效率 (18:55)
余票查询会显示还有多少张票,票数如果实时通过sell去计算,会影响性能,所以应该另外做张表,直接存储余票数
数据库设计,就是通过不同维护的表来描述一样事物
对于相对较固定的枚举类型,就可以用行转列来展示,目的就是方便查询,适合读多写少的场景
视图和存储过程在以前的项目中,经常用到,因为依靠数据库内部的算力,就可以帮我们做很多复杂的功能,但因为会占用较多的数据库资源,所以逐渐淘汰了,服务端资源不够可以加机器,数据库就不好加了,所以数据库资源很珍贵,这也是为什么会有数据缓存
12-3 生成车次时初始化余票信息 (23:17)
单向嵌套循环
for i = 0
for j = i
批量操作都应该考虑是否要加事务,如果跑一半失败了,是全部回滚?还是跑多少算多少?
面试经常问到:事务的传播机制,其实就是事务有嵌套时,要让事务怎么做,是外层决定内层,还是内层不管外层
阶梯价格是比较常见的设计,比如:
0100公里:0.4元/公里200公里:0.3元/公里
100
坐了一趟车,开了150公里,那么票价=100*0.4+(150-100)*0.3
12-4 生成车次时初始化各种座位的余票数量 (25:27)
12-5 为余票信息页面增加查询条件 (11:55)
12-6 为会员端增余票查询功能 (21:07)
本节分步进行,先做一个和控台一模一样的页面,再做修改,这样可以保存每步的提交记录,哪一步改砸了,可以随时回退。在工作中开发功能也是按这个流程来走,先拆分功能,再一步一步的实现
12-7 增加订票页面并实现车次信息传递 (26:10)
12-8 订票页面勾选乘客并显示购票列表 (27:17)
如果遇到【查找我的所有的XXX】这样的功能,需要考虑数据量的问题
一种是限制我的XXX的数量,在新增的时候,做校验,如果超过100,就不能再新增
一种是限制查询的数量,最多返回前100条数据
12-9 分解选座购票功能的前后端逻辑 (20:32)
12306规则:
只有全部是一等座或全部是二等座才支持选座
余票小于一定数量时,不允许选座(本项目以20为例)
选座效果:

座位类型枚举:

构造两个重要的响应式变量:
1 | |
座位售卖详情,比如有ABCDE五个站,sell=0110,则AB未被购买,AC已被购买

后端购票逻辑,分成选座和不选座
不选座,以购买一等座为例:遍历一等座车厢,每个车厢从1号座位开始找,未被购买的,就选中它
选座,以购买两张一等座AB为例:遍历一等座车厢,每个车厢从1号座位开始找A列座位,未被购买的,就预选中它;再挑它旁边的B,如果也未被购买,则最终选中这两个座位,如果B已被购买,则回到第一步,继续找未被购买的A座。
从第二个座位开始,需要计算和第一个座位的偏移值,可以减少循环,提高选座效率
12-10 订票页面增加选座效果 (35:38)
前后端都得加校验,前端校验可以减轻后端压力,后端校验是真实的校验。
后端不要相信前端,比如一些非空校验,不能前端有校验了,后端就省了
关于本节的第一个提交,copy出一个临时变量用于扣减库存,大家可以试试不用临时变量,而直接用seatTypes去扣减,在存在足够时,反复提交多次订单后,会有什么效果
computed和watch类似,都可以用来响应式的计算一个值,compute可以像第二个提交这样写,直接声明出一个响应式变量
本节提到多次,常见的代码设计:如果一个操作可以反复多次,则可以清空上一次的操作,再重新赋值,避免上一次的数据对本次的操作造成影响
12-11 增加确认订单表并生成前后端代码 (13:00)
对于重要的功能,我们要在接口入口落库,留下痕迹,方便做统计。
主键一般跟业务无关,每次重新生成数据,ID都会变;唯一键一般跟业务有关,每次重新生成数据,唯一键数据不会变
12-12 后端增加确认下单购票接口 (18:44)
本节没有测试,最终的代码有问题,将在下个小节一起测试并修复
常见的安全性校验:后端需要做好参数合法性校验,防止黑客绕过界面,直接访问接口
springboot在接收参数时,可以将json数组映射成List
后端校验分为两种:
1. 数据合法性校验:必输、长度、格式
2. 业务合法性校验:表数据是否存在?日期范围是否合理?
12-13 确认下单接口数据初始化 (15:08)
MemberIntercepter:会员拦截器,用于将当前登录的会员放到线程本地变量。要想使用这个功能,需要在SpringMvcConfig里配置下,打开这个功能
12-14 预扣减库存并判断余票是否足够 (13:44)
本节的扣减余票数功能使用的是switch case,去获取一个对象的不固定的属性,就会用到反射,反射性能不如直接写分支判断
12-15 计算多个选座之间的偏移值 (23:23)
计算出offsetList,偏移值,如果只有一个座位,就是{0},如果选择多个座位,例如三个:{0, 1, 2}
所以,通过第一个座位的列号column和offsetList,就可以知道本次的选座
12-16 循环获取每个车厢的每个座位 (22:28)
12-17 根据座位销售详情判断本次是否可选(一) (14:47)
抱歉!!本节所说的按位与,说错了,应该是按位或
位运算性能较好,特殊的场景可以优先考虑位运算。
sell的设计应该反过来说,因为位运算性能好,所以才设计了存储01的sell字段
常用的程序设计:约定优于配置
12-18 根据座位销售详情判断本次是否可选(二) (19:27)
12-19 完成有选座的挑座位逻辑 (24:30)
选座只能在同一个车厢
约定:车厢号从1开始,座位号从1开始,站序从0开始
12-20 保存最终的选座结果 (17:09)
12-21 选座成功后更新各座位的销售详情 (11:31)
尽量做短事务,不要做常事务,否则会大量占用数据库资源
本类方法间的调用,事务不生效
在遇到数组、列表、日期计算的时候,要注意边界值
对于复杂的SQL,可以写自定义mapper,具体参照本节的DailyTrainTicketMapperCust