ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信小程序校园班车查询与座位预约系统设计解析

微信小程序校园班车查询与座位预约系统设计解析 每年毕设开题季“微信小程序”这几个字能撑起半个计算机学院的题目清单。但同样是做小程序有人交出来就是“换皮商城”有人却能靠一个题目把并发控制、状态机、请求缓存全部讲清楚。今天想复盘一个我反复打磨过的方向——基于微信小程序的校园班车时刻表查询与座位预约系统。表面看它只是把一张校园班车时刻表搬进手机真正做下去你会发现座位预约背后的锁、状态流转和超时释放才是这个项目的灵魂也正好是答辩时最能拉开档次的内容。这个系统解决的是校园通勤里一个非常具体的矛盾高峰时段校车运力有限学生只能靠运气排队发车间隔不透明到了站点才发现上一班刚走好不容易挤上车又发现没座位要站十几分钟。有了小程序之后学生能提前看到当天所有班次、每个班次剩余座位自己选座预约到点直接核销上车。司机和管理员也能从后台提前知道这趟车大概有多少人需不需要加开一班。适合谁参考计算机专业毕业生、想在小程序里做预约类系统的开发者甚至负责后勤管理的老师都可以拿它当蓝本——只要目标是把“查询预约”这条链路做扎实。1. 为什么校园班车需要一个专门的预约小程序很多同学看到“校园班车”四个字第一反应是这不就是把一张Excel时刻表做进小程序吗实际上真不是。你只要在早八前站到校车站看过一次就会明白问题远不止“时刻表不清晰”这么简单。1.1 早八高峰的真实痛点看起来够坐实际永远不够坐我在做需求调研那几天蹲了三个早高峰和一个晚自习下课高峰观察到的现象很直接早上7:40到8:10是最大高峰每条线路基本趟趟满员后排站着七八个人晚上9:30之后末班车时间不固定很多同学在风里等了二十分钟才知道“最后一班已经走了”。司机师傅给我的反馈更有意思他说最怕的不是路堵是高峰期不知道后面还有多少人要来没办法判断要不要申请加开一辆加班车。站点排队的人也只能干等没有任何一个渠道能看到“这趟还有几个座”。这些痛点落到系统需求上就是三件事第一把每天每个班次的准确时刻表数字化第二把每个班次的实时余座亮出来第三允许学生提前预约座位减少现场不确定性。注意这里并没有“要一辆车的实时GPS轨迹”这种需求那是另一个量级的工程后边我会专门讲为什么不做。1.2 需求收集不能只抄模板我实际调研了什么现在网上随便一搜就有大量“校园巴士管理系统”需求文档这些文档结构化程度很高但最大的问题是没跟真正坐车的人聊过。我这次调研只做了三件事蹲点发车点记录每趟高峰班车的实际上座人数比如周五下午那趟车经常超员周日上午的班次却空一半数据波动非常大找司机师傅聊问他们管理上最缺什么信息答案是“下一波还有多少人”在班级群发了一个只能填三项的问卷问大家坐校车最烦什么。收回来的七成回答集中在“到了才发现没座位”和“不知道下一班还要等多久”。这三件事交叉下来核心需求排序就很清楚了余座信息加预约能力优先级大于路线站点详情大于车辆实时位置。很多毕设项目习惯把地图轨迹做成亮点但在这个题目里做轨迹既增加前端复杂度数据源的准确性也很难保证反而把真正的核心链路带偏了。所以我的结论是先做时刻表查询再做座位预约地图轨迹可以作为后期扩展方向而不是首版需求。1.3 功能边界的取舍哪些功能坚决不做一个毕设项目如果什么都想做通常什么都做不深。我当时列了一个“不做清单”不做在线支付因为校园接驳车多数是免费或刷卡支付会引入退款、风控这些无关因素不做用户社区和失物招领板块那跟“预约”核心链路毫无关系不做车辆实时轨迹图因为车辆GPS定位涉及硬件设备不是一个前端小程序能凭空实现的不做聊天客服顶多放一个后勤值班电话。最后保留的学生端功能是查看线路班次、按日期查看当天时刻表、余座展示、座位选择预约、取消预约、我的预约记录、订阅消息提醒。管理端功能是线路维护、班次生成、预约数据列表、二维码核销。把主线做透比堆一堆花哨页面有价值得多。2. 技术选型与整体架构原生小程序还是uni-app这个题目最热门的技术路线无非两条原生微信小程序开发或者uni-app跨端开发。我在正式动手前也犹豫过毕竟uni-app能顺带出App版本听起来很划算。但把毕设这个特殊场景摆进去结论其实很明确。2.1 原生开发在毕设场景下的优势先看对比对比维度原生微信小程序uni-app开发语言JavaScript WXML WXSSVue语法需要编译层转换调试效率微信开发者工具直接热更新需要HBuilderX编译到小程序端问题排查报错定位到原始代码报错链多一层编译映射难定位跨端能力仅微信可发布到App、H5、支付宝小程序答辩可讲内容原生组件、小程序生命周期、分包多端适配、Vue响应式原理这张表最关键的一行是“答辩可讲内容”。原生开发能让你直接面对微信小程序自己的生命周期、缓存机制、导航栏适配这些都是考官熟悉且会追问的。uni-app确实跨端但一个毕设项目通常只需要跑在微信里那“跨端”这个优点就没有用武之地反而要在答辩时解释“为什么Vue代码会有些微信里才出现的问题”徒增风险。另外从审核角度讲原生版本在提审、发布、体验版测试时的行为最可控不容易因为编译层差异出现“工具里正常、真机上样式错乱”的情况。2.2 云开发还是自建后端两条路线怎么选后端方案是另一个必须提前定的问题。微信云开发云函数加云数据库现在很成熟可以免去服务器部署特别适合时间紧的同学。但我个人更推荐计算机相关专业的学生选择自建后端典型组合是Spring Boot加MySQL原因是数据库表设计、事务回滚、接口鉴权这些内容在答辩里全部是真考点。我建议两条路线的判断标准如下如果你对后端不熟目标只是顺利毕业那选云开发把云函数写好数据库集合设计合理一样能过如果你希望在答辩时拿出有真实业务深度的系统或者打算把这套代码当作品集找实习那就用Spring Boot加MySQL哪怕慢一点也值得。云开发的隐藏成本也要提前知道云函数冷启动第一次调用有时会让你等两三秒体验版高峰期可能被平台限流免费额度够用但数据库读写次数、云函数调用次数在开学高峰那几天有可能超。自建后端就没有这些平台限制只要服务器带宽够处理三五万用户的学校场景绰绰有余而且你能完全掌控事务和锁。2.3 整体数据流与部署形态我最终采用的架构很朴素原生微信小程序前端请求到Spring Boot后端API后端连MySQL数据库部署在一台2核4G的云服务器上。用户登录流程是小程序端调用wx.login拿到code传给后端后端再拿code换openid生成一个自定义登录态token返回给小程序后续请求都在header里带这个token。管理员账号单独建数据库记录不做微信授权登录这样后台权限边界清晰答辩也更方便演示。整个链路不复杂但每一环都有明确分工小程序管页面交互后端管业务逻辑和数据一致性数据库管持久化。这也是我建议毕设保持的状态过度设计反而会让项目失控。3. 数据库设计座位与班次的数据关系才是核心这个项目里最不能拍脑袋设计的就是数据库。线路、班次、预约记录这三张表之间的关系如果没理清后面写查询和预约逻辑时每写一步都会别扭。3.1 核心表结构线路、班次、预约记录我设计的核心表如下这里先给出基础版本去掉了一些冗余字段方便大家理解主线。-- 班车线路表 CREATE TABLE bus_line ( id BIGINT PRIMARY KEY AUTO_INCREMENT, line_name VARCHAR(50) NOT NULL COMMENT 线路名称如A线, departure_station VARCHAR(50) NOT NULL COMMENT 起点站, destination_station VARCHAR(50) NOT NULL COMMENT 终点站, start_time VARCHAR(10) NOT NULL COMMENT 首班车时间, end_time VARCHAR(10) NOT NULL COMMENT 末班车时间, interval_minutes INT NOT NULL COMMENT 常规发车间隔, status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0停用, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- 班次表某个线路在具体日期的具体发车时间 CREATE TABLE bus_schedule ( id BIGINT PRIMARY KEY AUTO_INCREMENT, line_id BIGINT NOT NULL COMMENT 所属线路, banji_date DATE NOT NULL COMMENT 发车日期, departure_time VARCHAR(10) NOT NULL COMMENT 发车时间, capacity INT NOT NULL DEFAULT 45 COMMENT 座位总数, reserved_count INT NOT NULL DEFAULT 0 COMMENT 已预约人数, status TINYINT NOT NULL DEFAULT 0 COMMENT 0未发车 1已发车 2已取消, UNIQUE KEY uk_line_date_time (line_id, banji_date, departure_time), KEY idx_date_status (banji_date, status) ); -- 预约记录表 CREATE TABLE reservation ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 用户ID, schedule_id BIGINT NOT NULL COMMENT 班次ID, seat_row TINYINT NOT NULL COMMENT 座位排号, seat_col TINYINT NOT NULL COMMENT 座位列号, status TINYINT NOT NULL DEFAULT 0 COMMENT 0已预约 1已取消 2已过期 3已核销, reserve_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, cancel_time DATETIME COMMENT 取消时间, checkin_time DATETIME COMMENT 核销时间, UNIQUE KEY uk_schedule_seat (schedule_id, seat_row, seat_col), KEY idx_user_schedule (user_id, schedule_id) );这里最要紧的设计决策是bus_schedule 存的是“具体日期加发车时间”的班次实例而不是只存一套周期模板。如果你只存模板那么“本周五下午4点这趟车已满”这种状态就无处安放预约记录也没法挂靠到唯一的具体班次。虽然需要每天晚上或每周批量生成未来班次数据但这笔工作量换来的是状态管理上的清爽非常值得。3.2 座位唯一索引是防超卖的第一道防线座位预约最怕的就是“超卖”——明明只剩一个座两个用户同时下单都显示成功。在毕设项目里防超卖的核心手段不用搞得太复杂一个数据库唯一索引就足够了。reservation 表上的唯一约束 uk_schedule_seat (schedule_id, seat_row, seat_col)意味着同一个班次的同一个座位数据库层面只允许存在一条记录重复插入直接报唯一键冲突。当两个用户同时抢同一个座位时只有一个INSERT成功另一个会收到DuplicateKey错误后端捕获这个异常后返回“座位已被选择”即可。这种做法比悲观锁优雅也比Redis分布式锁简单得多。因为座位本身就是天然的唯一资源数据库唯一索引就是最强有力的约束。当然还需要配合事务让库存字段准确回补这一点我在第五章详细说。唯一索引的代价也很清楚数据库需要维护索引预约记录多的时候插入会略慢但对校园班车这种一天几千条预约的场景来说完全可以忽略。答辩时能把“为什么唯一索引能防止超卖”讲清楚就已经胜过了不少只会写增删改查的同学。3.3 预约状态机从已预约到已核销的四种状态预约记录的状态我用一个TINYINT字段表示状态码定义如下状态值状态名称触发条件说明0已预约用户预约成功正常等待乘车1已取消用户主动取消或超时取消座位需要释放2已过期发车时间到达且未核销座位需要释放并扣信用3已核销上车时扫码确认完成履约为什么不用字符串“waiting”“cancelled”这种写法两个原因数字状态在数据库中占空间小、索引效率高而且在代码里用switch做状态迁移判断非常直观。更关键的是状态机迁移必须由服务端控制不能允许“已过期”直接被前端改成“已核销”。我在 Service 里写了一个迁移校验方法任何更新操作必须带上当前状态和目标状态不匹配就抛异常。这个设计在答辩时是明显的加分点因为很多同学的状态字段就是从0改成1压根不校验合法路径。4. 时刻表查询模块列表分页与缓存策略的落地实现这个模块虽然是整个系统里最“peace”的部分但做好它直接决定了用户体验。一个校园班车信息查询页面如果每次进入都白屏三秒用户马上就会关掉。实际开发中我把缓存、分页、顶部导航适配都做了处理。4.1 接口设计与页面结构后端提供的核心查询接口如下GET /api/line/list——返回所有启用线路的基本信息调用频率低适合长缓存GET /api/schedule/list?lineId1date2025-05-20page1size10——返回某线路某日期的班次列表包含每个班次已预约人数GET /api/schedule/detail?scheduleId123——返回班次详情和座位图预约页面打开时调用小程序端页面结构分三层首页展示线路列表点击线路进入班次列表页顶部是一排横向滚动的日期Tab默认选中当天班次列表再往下是分页数据每个班次卡片显示发车时间和余座数点击某个班次进入详情页底部弹出座位图学生选座确认预约。这套页面结构和用户心智是匹配的从线路到班次到座位每一步递进都清晰。4.2 时刻表缓存的正确姿势缓存多久、怎么失效班车时刻表有一个特点一天之内极少变动但余座情况每秒钟都在变。所以缓存策略必须按数据分层处理。我的做法是const CACHE_KEYS { lineList: cache_line_list, scheduleList: (lineId, date, userId) cache_schedule_${lineId}_${date}_${userId} }; function getCache(key) { const data wx.getStorageSync(key); if (!data) return null; if (Date.now() data.expireTime) { wx.removeStorageSync(key); return null; } return data.value; } function setCache(key, value, seconds) { wx.setStorageSync(key, { value, expireTime: Date.now() seconds * 1000 }); }线路列表这种基本不怎么变的缓存600秒甚至一天都没问题班次列表要带着余座信息展示余座数据时效性要求高所以我只缓存60秒超过一分钟就重新拉取。特别注意一个坑班次列表缓存key里必须带上当前用户ID否则一个学生预约了座位另一个学生打开小程序直接读到了上一个人的缓存页面就会显示错误的余座数。很多同学写缓存不带用户维度这种问题在联调时非常隐蔽不容易发现。座位详情页我选择了彻底不做缓存。因为用户进入这个页面的目的就是选座如果展示的数据是几秒前的两个用户可能同时看到同一个空座很容易产生预期落差。为了这一点点性能去牺牲准确性不划算。4.3 列表触底加载与自定义导航栏高度班次列表和预约记录列表都需要触底加载。小程序里用onReachBottom这个页面生命周期触发配合分页参数实现Page({ data: { lists: [], page: 1, pageSize: 10, hasMore: true, loading: false }, async onReachBottom() { if (!this.data.hasMore || this.data.loading) return; this.setData({ loading: true }); const nextPage this.data.page 1; const res await request(/api/schedule/list, { lineId: this.data.lineId, date: this.data.date, page: nextPage, size: this.data.pageSize }); this.setData({ lists: this.data.lists.concat(res.list), page: nextPage, hasMore: res.list.length this.data.pageSize, loading: false }); } });重点说下自定义顶部导航栏高度的问题。如果毕设直接用了系统默认导航栏页面标题会很普通但只要想自定义导航就绕不开这个适配公式const menuBtn wx.getMenuButtonBoundingClientRect(); const { statusBarHeight } wx.getWindowInfo(); const navBarHeight (menuBtn.top - statusBarHeight) * 2 menuBtn.height;原理很简单微信胶囊按钮在顶部呈居中排列从状态栏底部到胶囊按钮顶部的距离是固定的这个间距乘以2再加上胶囊本身的高度就是自定义导航栏应有的总高度。我在不同机型上测试过用这个公式计算出来的导航栏位置和系统导航基本一致。如果不做这个适配iPhone SE和iPhone 15 Pro Max上同样的页面导航栏要不顶到边上要不空一大截视觉效果很糟。5. 座位预约核心从锁库存到超时释放的完整时序进入这个章节才是整个项目的重头戏。预约动作看起来只是插入一条预约记录但要让它在高峰并发下不超卖、可取消、能正常回补库存必须把时序和细节抠干净。5.1 预约接口执行顺序先锁库存再抢座位我推荐的后端执行逻辑如下放在同一个事务里校验班次存在且状态为未发车校验当前时间距离发车时间至少30分钟否则不允许预约执行原子更新尝试给班次加库存UPDATE bus_schedule SET reserved_count reserved_count 1 WHERE id #{scheduleId} AND reserved_count capacity AND status 0;如果上一步影响行数为0说明班次已满或已发车直接返回“该班次已满”或“已停止预约”如果上一步影响行数为1继续插入预约记录插入时如果命中唯一索引冲突说明这个座位刚被别人抢走需要回滚库存再返回“座位已被选择”。这个顺序为什么重要核心原因是先锁库存再抢座位能保证“整个班次不会超卖”的强约束在最前面生效。反过来如果先插入预约记录再更新库存就会出现一种中间态预约记录已经存在但reserved_count还没来得及加一此时另一个请求看到的是“余座还有”实际座位可能已经被占数据就不一致了。而且先插入后更新失败回滚时要同时删预约记录和扣库存逻辑更绕。先更新库存再插记录失败时只需要把reserved_count减回去清晰得多。库存回滚操作要放在catch块里并且必须和插入操作在同一个事务中。我用Spring的Transactional注解包裹整个方法任何一步抛异常数据库自动回滚不会出现“库存减了但座位没成功”或“座位成功但库存没变”的尴尬状态。5.2 取消预约与回补库存的顺序问题取消预约看似简单实际上也有一个顺序陷阱。正确做法是先更新reservation状态为已取消再更新bus_schedule把reserved_count减一两步同样放在一个事务里。原因很简单如果反着来先减库存再改状态用户连续点击两次取消按钮第二个请求进来发现状态还是“已预约”又执行了一次库存减一库存就会越减越多出现“余座数大于实际可用座位数”的脏数据。先改状态再加一层业务校验只有状态为已预约的记录才允许执行取消逻辑第二次点击时状态已经是已取消直接返回“重复操作”。另外我加了一个限制发车前30分钟不允许取消。这个时间门槛不是拍脑袋定的是跟司机师傅确认过的——临近发车时座位基本定型频繁的取消和重新分配会让他没法判断到底有多少人坐车。这个业务规则在答辩时可以顺势讲出一层“你们是怎么和真实用户确认业务边界的”比单纯讲CRUD有说服力得多。5.3 发车前过期未乘车定时任务处理方案总有人预约了座位但睡过头或临时改主意人没到车上座位却一直占着。如果不处理余座数据会越来越失真。我的方案是用Spring Boot的Scheduled定时任务每分钟扫描一次Scheduled(fixedDelay 60 * 1000) Transactional public void expireReservations() { ListReservation expiredList reservationMapper.findExpired( LocalDate.now(), LocalTime.now().minusMinutes(10)); for (Reservation r : expiredList) { reservationMapper.updateStatus(r.getId(), 0, 2, LocalDateTime.now()); scheduleMapper.decreaseReserved(r.getScheduleId()); } }这里有一个关键细节过期判断不能只看“发车时间已经过了”还要给乘客留出10分钟的核销宽限期。比如发车时间是8:00那8:10之前依然允许核销8:10一到还没核销的记录统一标记为已过期。每条过期的预约记录都需要单独回补一次库存不能用一个简单的“reserved_count减去N”的SQL批量处理因为不同预约记录可能对应不同班次。循环处理虽然慢但每分钟几百条记录的范围对数据库压力很小胜在准确。这一步做完整个系统的状态循环就闭环了预约、取消、过期、核销每个状态都有明确去向。5.4 订阅消息提醒一次性订阅的正确用法预约完成后的消息提醒用的是小程序的订阅消息能力。这里学生最常踩的坑是以为用户点了“允许”就能无限发消息。实际上微信的一次性订阅规则是用户每点击一次授权按钮你才能给他发送一条模板消息。预约时收集到一次订阅发送完“预约成功通知”就没了之后想再发“发车前提醒”还需要用户再次授权。所以我在预约成功页放了一个订阅授权面板把“发车提醒”这个模板单独让用户再点一次授权收集两条订阅额度一条用于通知预约成功一条用于发车前提醒。发送接口由后端调用不能在小程序端直接发。模板消息的文案要写清楚“什么时间、哪个班次、还剩几分钟发车”这样用户看到推送才会及时行动。这一个功能虽然小但它在答辩演示中效果很好能让老师看到你考虑了“用户会不会遗忘”这个真实问题。6. 真机测试与收集反馈阶段最容易踩的坑功能开发完以后真正折磨人的是联调和体验阶段。我见过太多项目在开发者工具里跑得好好的一上传体验版就凉了问题基本都出在下面这几个环节。6.1 预览码和体验版的区别给导师试用选哪种很多同学习惯点开发者工具里的“预览”按钮把生成的二维码发给导师结果导师打开没几分钟二维码就失效了。这是因为预览二维码是临时的主要给开发者自己快速调试用。想收集几天的使用反馈正确姿势是走“上传体验版”的流程对比维度预览二维码体验版有效期短临时可用相对稳定可持续成员管理不限制扫码人但很快就过期需要在后台添加体验成员用途本地快速验证给测试用户持续体验、收集反馈上线要求无不要求正式发布但必须配好域名具体步骤是在开发者工具点击“上传”代码会变成一个开发版本到微信公众平台的“版本管理”里把这个版本设为体验版然后在“成员管理”里把导师微信号添加为体验成员。导师之后扫码就能打开体验版只要你不主动替换版本或删除项目它就能一直供试用。收集到的反馈可以自然沉淀到后端日志和预约记录里比如哪个班次真实乘坐人数和预约人数差距最大这本身就是很宝贵的分析数据。6.2 合法域名配置开发者工具能跑、真机全挂这个坑几乎是所有小程序毕设都会遇到的。在开发者工具里你可以勾选“不校验合法域名”来绕过域名限制局域网IP、localhost都能请求。但一旦到真机的体验版这个勾选不会生效所有wx.request都会因为域名不合法被微信直接拦截页面会全部空白只剩请求失败日志导师看到就以为系统坏了。正确做法是提前准备一个已备案的HTTPS域名解析到后端服务器然后在微信公众平台“开发管理-服务器域名”里把request合法域名加上。注意几个细节域名必须是HTTPS不能用IP直接配置开发阶段如果要改接口路径后台配置完域名后通常有几分钟生效延迟还有一个小技巧是先把域名配好再上传体验版免得到体验版环境里排查半天还是404。注意开发者工具里勾选“不校验合法域名”只能用于本地调试体验版和正式版都不会生效。域名配置必须提前完成否则真机测试阶段会全线崩溃。6.3 请求封装与token过期跳转小程序端所有的网络请求如果都靠wx.request裸请求代码会非常散乱。我封装了一个统一请求函数把基础URL、header、错误码处理都收敛到一处const request (url, data {}, method GET) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method, data, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) || }, success(res) { const { code, data, message } res.data; if (code 200) { resolve(data); } else if (code 401) { wx.removeStorageSync(token); wx.reLaunch({ url: /pages/login/login }); reject(new Error(message)); } else { reject(new Error(message)); } }, fail(err) { reject(err); } }); }); };这个封装的收益不只体现在少写几十行代码更重要的是统一了错误处理。当token过期时任何页面发起请求都会得到401然后统一跳回登录页。如果每个页面都自己调wx.request就会有的页面跳登录、有的页面弹窗报错体验参差不齐。对于“我的预约记录”这种进入时必须校验登录态的页面统一跳转机制能让整个流程顺畅很多。6.4 高峰期“全民抢座”的缓存击穿思路校园班车的预约高峰很有特点不是随机分布而是集中在开课前半小时。比如早八前整栋宿舍楼的学生同时打开小程序如果每次查询都打到数据库后端压力会瞬间拉满。我的缓解方案有两层第一把余座数量这种实时但变化不够剧烈的数据在服务端做一层定时缓存每个班次每5秒刷新一次响应速度大幅提升查询压力从每秒几十次降到每秒一次第二真正的写操作也就是预约、取消不做缓存仍然走数据库事务保证数据一致性。如果学有余力还可以在答辩扩展示介绍Redis方案用Redis的INCR或DECR做预扣库存写入MySQL作为持久化记录Redis负责高性能MySQL负责最终一致。但坦白讲对毕设场景第一步的定时缓存已经足够应对先把一致性问题解决再谈性能优化。7. 答辩时值得讲的亮点和后续扩展方向这个题目能讲的东西很多但有的同学答辩时只会展示“点一下按钮出现一个列表”最后被导师问倒。提前把几个技术深水区的内容准备好效果会完全不一样。7.1 导师可能会这样问你如何兜住这些技术细节每年答辩导师对“小程序预约”类题目的提问都是有套路的。我整理几个最常见的问题和准备思路问两个学生同时抢最后一个座位你的系统如何保证不超卖回答要点reservation表的(schedule_id, seat_row, seat_col)唯一索引是从数据库层拦截重复插入同时我的预约事务先原子更新bus_schedule的reserved_count只要更新行数不为1就返回满座两个约束叠加从源头杜绝超卖。问你的状态字段为什么用数字而不是字符串回答要点数字状态值适合索引和查询并且状态迁移都通过服务端校验不会出现非法状态跳变。问如果缓存里还有旧数据用户看到的余座不准怎么办回答要点线路缓存长班次列表缓存只有60秒座位详情不做缓存写操作永远走实时事务。问用户预约后不来怎么办回答要点定时任务在发车之后加10分钟宽限期超时标记为已过期并回补库存同时可以在扩展里加信用机制累计三次未乘车限制预约三天。这些问题准备充分答辩时回答起来就会像在讲自己的实际项目而不是背稿子。导师最怕的是学生做完项目但完全不懂为什么这么做这套内容正好能补齐“知其所以然”这一层。7.2 加分扩展蓝牙ibeacon自动核销、司机端、数据看板如果时间有余力这个题目还有几个自然延伸方向。第一个是司机端小程序司机通过小程序或工作台扫码核销比管理员手动看Excel更高效第二个是蓝牙ibeacon核销在车厢内放一个低功耗蓝牙设备学生靠近时微信小程序自动感知并完成核销可以顺带判断学生“确实上车了”而不只是“预约了”这是当前弱定位场景下比较务实的技术路线第三个是数据看板统计每个班次预约数、实际核销数、常取消用户辅助后勤判断要不要加开加班车。这些扩展不必全部完成甚至在答辩时只作为“后续计划”提一下都行但能展示你对真实业务的理解深度。我个人带完这个项目最大的体会是这类题目的出彩点根本不在页面多炫而在于那些看不见的小细节——每一次取消库存有没有准确回补每一个过期的座位定时任务有没有真正释放每一次高峰并发缓存和事务有没有配合好。把这些细节做扎实你讲出来的就是一个有真实业务深度的系统而不是又一张换皮的表单。准备开工的同学建议先把小程序账号、名称、服务器HTTPS域名一次性配置好这几个环境问题拖着最后一定会在答辩前几天集中爆炸。
返回列表