飞机售票系统课程设计实战:UML建模、数据库设计与防超卖订单状态机
发布时间:2026/9/17 17:49:25来源:尧图网络
简介这份资源是一份软件工程课程设计报告主题为飞机售票系统面向高校软件工程、计算机相关专业的学生以及需要完成课程设计或实验报告的学习者。报告以机票预定业务为背景完整呈现软件开发全流程可帮助读者理解如何把课堂上的软件工程方法论落到一个具体项目上。压缩包内共1个doc文档约432KB正文共52页目录依次包含项目开发计划书、软件需求规格说明书、设计规格说明书、源程序清单、测试报告与用户手册六大模块。其中需求部分给出查询、预定、取消预定等用例场景与术语定义设计部分涉及系统架构、界面与数据库设计测试部分记录功能、性能与兼容性测试结果并配有项目进度、人员分配与工作量估算表格。文档结构规范、章节齐全可直接作为课程设计报告的参考模板也便于读者对照仿写目录、补充自己的项目内容。目前已有1841人学习下载。1. 飞机售票系统课程设计真正要交的不只是52页文档很多人拿到「软件工程课程设计报告-飞机售票系统」这个题目第一反应是去搜一份52页的模板把UML图、数据字典和参考文献凑齐就交差。但答辩时被问一句「你的座位分配怎么保证不超卖」整页文档就露馅了。这门课设计的核心其实是一套可运行的订票链路从需求拆解、UML建模、数据库设计、核心算法到订单状态流转和测试用例文档只是把这条链路讲清楚。适合正在做软件工程课程设计、毕业设计选题落在售票/订票系统的同学阅读也适合用Python或Java做后端、需要一套可复现工程骨架的人。下面按「建模 → 建库 → 写代码 → 验证」的顺序把飞机售票系统从标题拆成能跑起来的东西。2. 飞机售票系统的需求分析与UML建模落地需求分析阶段最容易犯的错是把功能清单当需求写。飞机售票系统表面上就是查航班、选座位、下单、退票但真正决定后面数据库表结构的是角色边界和状态迁移。先把参与者固定下来再画图能省掉反复改表的时间。2.1 用例图里必画的六类参与者与用例常见做法是把参与者定为游客、注册会员、票务管理员、系统定时任务、支付网关、后台审计。前四类是人或内部任务后两类是外部系统。必画用例至少覆盖这些参与者核心用例容易漏掉的边界用例游客查询航班、注册未登录时能否看到剩余座位数会员下单、支付、退票、改签超时未支付的订单自动释放票务管理员航班增删改、舱位调整航班取消时的批量退款定时任务订单超时关闭、航班状态刷新与支付回调的时序冲突支付网关支付结果通知重复通知的幂等处理审计查询操作日志日志与订单状态的一致性画用例图时别把「登录」单独作为一个大用例去展开登录是前置条件不是业务主用例。真正要展开的是「下单」和「退票」因为这两条路径上挂着库存扣减、状态机和事务。2.2 类图、时序图与数据库表三者的映射关系软件工程课程设计报告里类图、时序图、数据库表经常各画各的最后对不上。我一般先画类图再让类图里的实体类直接对应到表。核心实体类大致是Flight航班、SeatInventory座位库存、Order订单、Ticket客票、Passenger乘机人、Payment支付流水。类之间的关系决定了外键Flight1 对多SeatInventory按舱位维度拆分。Order1 对多Ticket一个订单可以给多人出票。Order1 对 1 或 1 对多Payment取决于是否允许分次支付。时序图只画两条就够了一条是「会员下单到支付成功」一条是「会员退票到退款到账」。画时序图时把数据库操作作为参与者放进去这样后面写代码时事务边界一眼就能看出来。2.3 航班查询与座位分配的流程图表达软件工程流程图在这里不是装饰。航班查询的流程图要体现「先查缓存、再查数据库、最后合并剩余座位数」座位分配的流程图要体现「锁座 → 生成订单 → 支付 → 正式出票 → 超时释放」。如果题目里允许做多城市中转推荐可以在查询模块里加一个最短路径计算。常见做法是用 Floyd 或 Dijkstra 算城市之间的最低票价路径流程图里表现为「中转推荐」分支——先查直飞再查最多两段中转最后按总价和时间排序。注意流程图里的每个判断节点最后都要能在代码里找到对应的 if 或 while否则报告和实现会脱节。3. 飞机售票系统数据库设计与核心算法实现建库这一步决定了后面代码能不能写顺。飞机售票系统的数据库难点不在表多而在库存字段的并发安全和订单状态的一致性。先把表结构定死再谈算法。3.1 航班表、座位表、订单表的字段与约束我一般用三张主表加两张辅助表-- 航班表 CREATE TABLE flight ( flight_id BIGINT PRIMARY KEY AUTO_INCREMENT, flight_no VARCHAR(16) NOT NULL UNIQUE, dep_city VARCHAR(32) NOT NULL, arr_city VARCHAR(32) NOT NULL, dep_time DATETIME NOT NULL, arr_time DATETIME NOT NULL, status TINYINT NOT NULL DEFAULT 1 -- 1正常 2取消 3延误 ); -- 座位库存表按航班舱位维度 CREATE TABLE seat_inventory ( inventory_id BIGINT PRIMARY KEY AUTO_INCREMENT, flight_id BIGINT NOT NULL, cabin_class VARCHAR(16) NOT NULL, -- 经济舱/商务舱 total_seats INT NOT NULL, sold_seats INT NOT NULL DEFAULT 0, price DECIMAL(10,2) NOT NULL, version INT NOT NULL DEFAULT 0, -- 乐观锁版本号 UNIQUE KEY uk_flight_cabin (flight_id, cabin_class) ); -- 订单表 CREATE TABLE order ( order_id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE, user_id BIGINT NOT NULL, flight_id BIGINT NOT NULL, cabin_class VARCHAR(16) NOT NULL, seat_count INT NOT NULL, amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL DEFAULT 0, -- 0待支付 1已支付 2已出票 3已退票 4已关闭 expire_time DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP );字段说明seat_inventory里的version是乐观锁版本号sold_seats不能超过total_seats这个约束建议在应用层和数据库层都做。order表的expire_time用于定时任务关闭超时订单status的取值要和后面状态机一致。3.2 用SQL建表并加锁防止超卖超卖是飞机售票系统课程设计里最容易被追问的点。常见做法有两种悲观锁和乐观锁。悲观锁写法START TRANSACTION; SELECT sold_seats, total_seats FROM seat_inventory WHERE flight_id ? AND cabin_class ? FOR UPDATE; -- 应用层判断 sold_seats n total_seats UPDATE seat_inventory SET sold_seats sold_seats ? WHERE flight_id ? AND cabin_class ?; COMMIT;乐观锁写法UPDATE seat_inventory SET sold_seats sold_seats ?, version version 1 WHERE flight_id ? AND cabin_class ? AND version ? AND sold_seats ? total_seats; -- 影响行数为0则说明并发冲突或库存不足重试或直接失败参数说明?依次是购买数量、航班ID、舱位、版本号、购买数量。乐观锁适合并发不高的课程设计场景悲观锁更直观但容易在答辩时被问「锁的粒度是不是太大了」。两种都要在报告里写出适用场景和缺点。提示无论用哪种锁订单表和库存表的更新必须在同一个事务里否则支付回调和库存扣减会出现不一致。3.3 航班路径查询与座位分配算法航班查询我一般分两步先按出发城市、到达城市、日期查直飞如果没有直飞或用户勾选了中转再跑一次多段查询。多城市最低票价可以用 Floyd 算法预计算城市间的最低价适合城市数量不大比如50个以内的课程设计。伪代码# dist[i][j] 表示城市 i 到 j 的最低票价 for k in range(n): for i in range(n): for j in range(n): if dist[i][k] dist[k][j] dist[i][j]: dist[i][j] dist[i][k] dist[k][j] path[i][j] path[i][k] # 记录中转点座位分配算法相对简单同一订单尽量分配相邻座位。常见做法是按排和列遍历可用座位找到连续的空位就锁定。如果是课程设计做到「同舱位随机分配 尽量相邻」就够了不用引入复杂的图着色。4. 飞机售票系统订票主链路的代码实现数据库定好之后订票主链路就是一条事务加一个状态机。这一章用 Python 写一个最小可运行版本重点看事务边界和状态迁移语言换成 Java 或 Go 逻辑一样。4.1 订票接口的事务边界与并发控制订票接口要做的动作有校验参数、检查库存、扣减库存、生成订单、返回支付链接。这几步必须在同一个事务里否则会出现「库存扣了但订单没生成」的脏数据。import pymysql def create_order(conn, user_id, flight_id, cabin_class, seat_count): with conn.cursor() as cur: try: conn.begin() # 1. 乐观锁扣减库存 cur.execute( UPDATE seat_inventory SET sold_seats sold_seats %s, version version 1 WHERE flight_id %s AND cabin_class %s AND version %s AND sold_seats %s total_seats , (seat_count, flight_id, cabin_class, version, seat_count)) if cur.rowcount 0: raise Exception(库存不足或并发冲突) # 2. 生成订单 order_no gen_order_no() cur.execute( INSERT INTO order (order_no, user_id, flight_id, cabin_class, seat_count, amount, status, expire_time) VALUES (%s, %s, %s, %s, %s, %s, 0, DATE_ADD(NOW(), INTERVAL 15 MINUTE)) , (order_no, user_id, flight_id, cabin_class, seat_count, amount)) conn.commit() return order_no except Exception as e: conn.rollback() raise e逻辑说明先扣库存再插订单顺序不能反。version需要先从seat_inventory查出来查和更新之间如果被其他事务修改更新就会失败。参数里的seat_count同时出现在库存判断和订单写入里保证两处一致。支付回调和定时任务关闭订单也要更新order.status并且只能从「待支付」迁移到「已支付」或「已关闭」。4.2 退改签状态机设计订单状态迁移必须收敛否则同一订单可能被退两次。我一般把状态机写成一个字典ORDER_TRANSITIONS { 0: [1, 4], # 待支付 - 已支付 / 已关闭 1: [2, 3], # 已支付 - 已出票 / 已退票 2: [3], # 已出票 - 已退票 3: [], # 已退票 终态 4: [], # 已关闭 终态 } def can_transition(cur_status, next_status): return next_status in ORDER_TRANSITIONS.get(cur_status, [])退票时要恢复库存并且要区分「已出票退票」和「未出票退票」的手续费逻辑。改签可以理解为「退旧票 买新票」的组合但要在同一个事务里完成避免中间态被其他请求看到。4.3 Python最小可运行订票流程把前面的片段串起来一个最小流程如下def book_ticket(user_id, flight_id, cabin_class, seat_count): conn pymysql.connect(hostlocalhost, userroot, password123456, databaseticket_system) try: order_no create_order(conn, user_id, flight_id, cabin_class, seat_count) # 模拟支付回调 pay_order(conn, order_no) # 模拟出票 issue_ticket(conn, order_no) return order_no finally: conn.close()参数说明user_id是会员主键flight_id加cabin_class定位库存行seat_count同时参与库存判断和订单金额计算。跑通这条链路后再补上超时关闭和退票接口课程设计的核心功能就齐了。5. 验证方法与答辩排错从52页报告到可运行系统代码能跑不等于报告能过。课程设计答辩通常只给几分钟评委看的是「你是不是真的懂这个系统」而不是文档页数。验证要从测试用例和报告一致性两头抓。5.1 订票主线的测试用例设计至少准备这几条测试用例每条都要在报告里写清楚预期结果和实际结果用例编号场景预期结果TC-01正常下单并支付订单状态变为已出票库存减一TC-02库存只剩1张两个请求同时下单一个成功一个提示库存不足TC-03下单后15分钟不支付定时任务关闭订单库存恢复TC-04已出票订单发起退票状态变为已退票库存恢复TC-05重复支付回调订单只出票一次幂等生效跑测试时把数据库事务日志和订单状态变更记录都截下来放进报告附录比贴大段代码更有说服力。5.2 报告评审中最常见的失分项最常见的失分点不是功能少而是图和实现对不上类图里有六个实体数据库只有三张表时序图里画了缓存代码里没有用例图里的「支付网关」在代码里只是一个 print。还有一种是被问「为什么用乐观锁不用悲观锁」时答不出并发场景。一个具体技巧在报告最后一页放一张「代码文件与UML图对应关系表」把每个.py或.java文件对应到哪张图、哪个用例写清楚。评委翻到这里基本不会再追问模块划分。另外把version字段和状态迁移字典单独打印一页答辩时直接翻到这页比口头解释快得多。本文还有配套的精品资源点击获取
网站建设高端定制企业官网