尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

数据库课程设计实战:飞机订票系统从建模到并发验证

发布时间:2026/9/26 1:43:21

资讯中心
01
ARTICLE

数据库课程设计实战:飞机订票系统从建模到并发验证

数据库课程设计实战:飞机订票系统从建模到并发验证
简介本资源是一份面向高校数据库课程学习者的《飞机订票系统》课程设计完整报告聚焦数据库原理与应用实践帮助学生掌握需求分析、ER建模、逻辑表设计含乘客、航班、座位、订单等核心表、功能模块划分登录、查询、订退票、支付、财务统计及界面设计全流程。文档结构严谨覆盖概述、需求分析、数据库逻辑设计、软件功能结构图、模块流程说明及结束语共六章内容详实且具备可复现性适合作为数据库课程设计参考范本或期末项目对标案例。资源为单文件PDF格式共1个文件大小762KB轻量易读便于课堂展示与课后研习。已有14038人学习下载文中ER模型图、表结构定义、整体业务流程图及各模块功能描述均为教学重点可直接用于课程作业借鉴、答辩材料准备或数据库建模能力提升。1. 为什么一个“飞机订票系统”课程设计能卡住90%的数据库初学者不是因为SQL写不全也不是因为ER图画不准——而是你把“数据库课程设计”当成了期末作业交差任务却没意识到它其实是你第一次完整经历从现实业务约束反推数据结构、用工具链固化建模逻辑、再通过代码验证事务边界的闭环训练。我带过三届数据库课设最常看到的翻车现场是学生花两周写出200行Java Swing界面却在第15天发现“同一航班两个用户同时点“确认预订”后余票数变成-1”而调试时连事务隔离级别在哪改都不知道。这个PDF标题背后藏着Oracle 11g的锁机制实操、PowerDesigner里主外键自动生成DDL的陷阱、Eclipse中JDBC连接池配置的玄学参数——它不是文档是数据库工程能力的体检报告。适合刚学完范式理论、但没碰过真实并发场景的本科生也适合想补足“设计→建模→实现→压测”全链路的转行者。接下来我会带你用一套可复现的最小可行路径把这份PDF里的抽象需求变成能在本地跑通、能查日志、能模拟抢票的实体系统。2. 用PowerDesigner 16.5逆向生成物理模型从手绘ER图到Oracle 11g DDL脚本的3个关键跳转PowerDesigner不是画图软件它是把业务语言翻译成数据库语法的编译器。很多同学直接拖拽画完ER图就导出SQL结果在Oracle里执行报错“ORA-00907: missing right parenthesis”根本原因是没理解PowerDesigner里概念模型CDM→逻辑模型LDM→物理模型PDM这三层转换的强制约束。下面这三步是我反复验证过的最小安全路径。2.1 先在CDM层定义业务实体与关系禁用自动继承打开PowerDesigner → File → New Model → Conceptual Data Model → 确认DBMS为“Generic”。重点操作创建实体时右键实体 → Properties → Entity → 在“Code”栏手动输入英文名如Passenger不要用中文或空格这是后续生成DDL的关键关系连线后双击关系线 → Properties → Cardinality → 严格设置基数如“航班”与“座位”是1:N必须勾选“Mandatory”表示非空禁用自动继承Tools → Model Options → Notation → 取消勾选“Inheritance notation”否则导出时会生成Oracle不支持的SUBTYPE OF语法。提示CDM层只管“谁和谁有关”不管字段类型。比如“乘客”实体下只写passenger_id、name不写VARCHAR2(50)——那是LDM的事。2.2 LDM层映射数据类型解决Oracle 11g的字符集陷阱CDM转LDM时PowerDesigner默认用Generic类型必须手动映射到Oracle 11g。操作路径Tools → Generate Logical Data Model → 选择目标DBMS为“Oracle 11g”。关键动作右键LDM中的任意属性 → Properties → Domain → 点击“Edit…” → 在Domain列表中创建新DomainName填VARCHAR2_50Data Type选VARCHAR2Length填50同理创建NUMBER_10_2对应票价、DATE_YMD对应起飞时间对所有字符串字段姓名、身份证号、航班号应用VARCHAR2_50特别注意身份证号不能用NUMBER类型——Oracle NUMBER最大精度38位但18位身份证含X校验码必须用VARCHAR2。-- PowerDesigner生成的典型字段定义正确 passenger_name VARCHAR2(50) NOT NULL, id_card VARCHAR2(18) NOT NULL, flight_no VARCHAR2(10) NOT NULL -- 错误示范常见翻车点 -- id_card NUMBER(18) -- 会导致插入11010119900307271X时报ORA-017222.3 PDM层生成DDL绕过Oracle 11g的表空间硬编码坑LDM转PDM后右键PDM → Generate Database → 选择“Oracle 11g” → 在“Selection”页签勾选所有表 → 点击“Preview”前务必做两件事Tools → Resources → DBMS → 找到Oracle 11g → Edit → 在“Script\Objects\Table\Create”模板中删除所有TABLESPACE USERS硬编码语句Oracle 11g默认表空间可能不是USERS且课程设计无需指定在“Options”页签 → 勾选“Generate DROP statements before CREATE” → 取消勾选“Generate ALTER statements for existing objects”。生成的DDL脚本中你会看到类似这样的建表语句-- 正确生成的CREATE TABLE语句无表空间有主外键约束 CREATE TABLE FLIGHT ( flight_no VARCHAR2(10) NOT NULL, departure_city VARCHAR2(20) NOT NULL, arrival_city VARCHAR2(20) NOT NULL, departure_time DATE NOT NULL, arrival_time DATE NOT NULL, total_seats NUMBER(4) NOT NULL, available_seats NUMBER(4) NOT NULL, CONSTRAINT PK_FLIGHT PRIMARY KEY (flight_no) ); CREATE TABLE BOOKING ( booking_id NUMBER(10) NOT NULL, passenger_id NUMBER(10) NOT NULL, flight_no VARCHAR2(10) NOT NULL, booking_time DATE NOT NULL, status VARCHAR2(10) DEFAULT CONFIRMED NOT NULL, CONSTRAINT PK_BOOKING PRIMARY KEY (booking_id), CONSTRAINT FK_BOOKING_PASS FOREIGN KEY (passenger_id) REFERENCES PASSENGER(passenger_id), CONSTRAINT FK_BOOKING_FLIGHT FOREIGN KEY (flight_no) REFERENCES FLIGHT(flight_no) );逻辑说明PowerDesigner生成的外键约束名如FK_BOOKING_PASS长度不能超30字符否则Oracle报ORA-00972DEFAULT CONFIRMED确保新订单状态初始化正确避免NULL值引发查询歧义。3. 在Oracle 11g中部署与验证从安装验证到事务隔离级别的实操校准装好Oracle 11g只是起点课程设计真正开始于你亲手验证“余票扣减”是否原子性。很多同学跳过这步直接写Java代码结果调试时发现数据不一致却找不到源头。3.1 验证Oracle 11g基础服务用SQL*Plus确认实例与监听器状态先确认Oracle服务已启动Windows下检查服务列表是否有OracleServiceORCLLinux下执行ps -ef | grep pmon。然后用SQL*Plus连接# Windows命令行 sqlplus /nolog SQL connect / as sysdba Connected. SQL select instance_name, status from v$instance; INSTANCE_NAME STATUS ---------------- ------------ orcl OPEN SQL select name, open_mode from v$database; NAME OPEN_MODE --------- -------------------- ORCL READ WRITE如果返回OPEN和READ WRITE说明实例正常。接着验证监听器lsnrctl status # 输出中应包含 Service orcl has 1 instance(s) 且状态为READY注意若lsnrctl status报“TNS-12541: TNS:no listener”需运行lsnrctl start若connect / as sysdba报ORA-12560检查Windows服务中OracleOraDb11g_home1TNSListener是否启动。3.2 手动执行核心业务SQL用UPDATESELECT验证余票扣减原子性在SQL*Plus中执行以下脚本模拟一次订票操作以航班CA123为例-- 步骤1查询当前余票 SELECT available_seats FROM FLIGHT WHERE flight_no CA123; -- 步骤2扣减余票关键必须用UPDATE而非SELECTUPDATE UPDATE FLIGHT SET available_seats available_seats - 1 WHERE flight_no CA123 AND available_seats 0; -- 步骤3检查UPDATE影响行数 SELECT SQL%ROWCOUNT FROM DUAL; -- 应返回1表示扣减成功 -- 步骤4再次查询确认余票 SELECT available_seats FROM FLIGHT WHERE flight_no CA123;现象若步骤2返回0行更新说明余票已售罄若返回1行步骤4的值比步骤1少1。这证明UPDATE的WHERE条件实现了“检查-扣减”原子操作无需额外加锁——这是Oracle MVCC机制保障的比手写SELECT FOR UPDATE更轻量。3.3 校准事务隔离级别解决“幻读”导致的重复订票Oracle默认隔离级别是READ COMMITTED但它无法阻止幻读Phantom Read。在高并发下两个用户同时查询CA123余票为1都通过WHERE available_seats 0结果都执行UPDATE余票变-1。解决方案是升级到SERIALIZABLE-- 在SQL*Plus中为当前会话设置 ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE; -- 或在Java JDBC连接URL中添加 -- jdbc:oracle:thin:localhost:1521:orcl?SetBigStringTryClobtruedefaultRowPrefetch100oracle.jdbc.defaultNChartrueoracle.jdbc.useFetchSizeWithLongColumntrueoracle.jdbc.ReadTimeout30000oracle.jdbc.SetBigStringTryClobtrueoracle.jdbc.defaultRowPrefetch100oracle.jdbc.useFetchSizeWithLongColumntrueoracle.jdbc.ReadTimeout30000oracle.jdbc.isolationLevel8提示SERIALIZABLE对应JDBC常量Connection.TRANSACTION_SERIALIZABLE值为8不是TRANSACTION_REPEATABLE_READOracle不支持该级别。4. Eclipse JDBC实现订票核心逻辑绕开连接池泄漏与事务回滚失效的3个血泪坑Eclipse不是IDE是你的数据库操作沙盒。很多同学在Eclipse里写完JDBC代码运行时报java.sql.SQLException: Io exception: Connection reset其实问题不在网络而在连接管理策略。4.1 创建最小JDBC连接工具类用try-with-resources确保物理连接释放不要用静态Connection单例课程设计阶段必须显式管理连接生命周期。创建DBUtil.javaimport java.sql.*; public class DBUtil { private static final String URL jdbc:oracle:thin:localhost:1521:orcl; private static final String USER scott; private static final String PASSWORD tiger; public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } // 关键提供带事务控制的获取连接方法 public static Connection getConnection(boolean autoCommit) throws SQLException { Connection conn getConnection(); conn.setAutoCommit(autoCommit); // false表示手动控制事务 return conn; } }在订票业务方法中必须用try-with-resourcespublic boolean bookFlight(String flightNo, int passengerId) { String sql UPDATE FLIGHT SET available_seats available_seats - 1 WHERE flight_no ? AND available_seats 0; try (Connection conn DBUtil.getConnection(false); // 关键autoCommitfalse PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, flightNo); int rows ps.executeUpdate(); if (rows 1) { conn.commit(); // 显式提交 return true; } else { conn.rollback(); // 余票不足回滚 return false; } } catch (SQLException e) { e.printStackTrace(); try { if (conn ! null !conn.isClosed()) { conn.rollback(); // 异常时强制回滚 } } catch (SQLException ex) { ex.printStackTrace(); } return false; } }逻辑说明try-with-resources自动调用close()但Connection.close()在Oracle JDBC驱动中实际是归还连接池若配置了池而非断开物理连接。课程设计未配连接池时它等价于conn.close()释放资源。4.2 配置Oracle JDBC驱动用ojdbc6.jar而非ojdbc8.jar兼容Oracle 11gOracle 11g官方支持的JDBC驱动是ojdbc6.jar对应JDK 1.6ojdbc8.jar虽能连但会触发ORA-28040: No matching authentication protocol错误。下载地址Oracle官网搜索“Oracle Database 11g Release 2 JDBC Drivers”。在Eclipse中添加Project → Properties → Java Build Path → Libraries → Add External JARs → 选择ojdbc6.jar验证驱动加载在main方法中加测试代码try { Class.forName(oracle.jdbc.driver.OracleDriver); System.out.println(Oracle JDBC Driver loaded successfully); } catch (ClassNotFoundException e) { System.err.println(Oracle JDBC Driver not found!); }4.3 调试事务回滚失效检查autocommit模式与连接复用最隐蔽的坑你在Service层调用bookFlight()但上层Controller又调用了getConnection()导致两个方法用不同Connection回滚只作用于局部连接。解决方案禁止在业务方法内new Connection所有Connection必须由调用方传入或用ThreadLocal存储Connection课程设计简单场景不推荐易内存泄漏更稳妥的做法在Service层统一开启事务用Spring声明式事务但课程设计通常不用Spring。// 正确Connection由入口方法统一管理 public void processBooking(String flightNo, int passengerId) { Connection conn null; try { conn DBUtil.getConnection(false); boolean success bookFlight(conn, flightNo, passengerId); // 修改bookFlight接收conn参数 if (success) { conn.commit(); } else { conn.rollback(); } } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) {} } } finally { if (conn ! null) try { conn.close(); } catch (SQLException e) {} } }5. 避坑指南课程设计中最常踩的5个深坑及现场急救方案这些不是理论错误是我在实验室亲眼看着学生重装Oracle三次、删库重建五遍后总结的实战排错清单。每一条都对应一个具体报错、一个定位命令、一个修复动作。5.1 现象PowerDesigner生成DDL后在SQL*Plus执行报ORA-00922: missing or invalid option原因PowerDesigner在PDM生成时默认勾选了“Generate storage clauses”导致DDL中出现STORAGE (INITIAL 64K)等Oracle 11g不识别的存储参数。解决Tools → Resources → DBMS → Oracle 11g → Edit → 在“Script\Objects\Table\Create”模板中删除所有STORAGE (...)及PCTFREE相关行。5.2 现象Eclipse运行Java程序报java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver原因ojdbc6.jar未加入Build Path或加入了但Eclipse未刷新常见于复制项目后忘记Refresh。解决右键项目 → Refresh若仍报错Project → Properties → Java Build Path → Order and Export → 勾选ojdbc6.jar → Apply。5.3 现象订票成功但FLIGHT表available_seats不变或变为负数原因UPDATE语句缺少AND available_seats 0条件或Java代码中未检查executeUpdate()返回值。解决在SQL*Plus中手动执行UPDATE语句确认返回行数Java中必须用if (rows 1)判断不能只看异常。5.4 现象多用户并发订同一航班余票扣减错误如从2变成0跳过1原因未设置事务隔离级别或Connection被多个线程共享static Connection。解决在业务方法开头加conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)确认Connection对象不被static修饰。5.5 现象PowerDesigner画完ER图生成LDM时部分属性丢失如ID字段消失原因CDM中实体属性未设置“Primary Identifier”主标识符PowerDesigner认为该属性不参与建模。解决双击实体 → Attributes → 找到主键字段如passenger_id→ 勾选“Primary Identifier”复选框 → 重新生成LDM。6. 用真实压力验证订票逻辑一个5行Shell脚本模拟100次并发抢票课程设计验收时老师不会只看你界面截图而是问“如果100个人同时抢一张票系统怎么保证不超卖”——这时候你需要拿出可复现的压力证据而不是口头解释。6.1 编写极简压力脚本用curl触发Java Web接口假设你用Servlet假设你已用Eclipse开发了一个BookServletURL为http://localhost:8080/airline/book?flightNoCA123passengerId1001。创建stress_test.sh#!/bin/bash # 模拟100次并发请求 for i in {1..100}; do curl -s http://localhost:8080/airline/book?flightNoCA123passengerId$((1000i)) done wait echo 100 requests completed赋予执行权限并运行chmod x stress_test.sh ./stress_test.sh6.2 验证结果用SQL直接查数据库状态压力测试后立即在SQL*Plus中执行-- 查看最终余票 SELECT available_seats FROM FLIGHT WHERE flight_no CA123; -- 查看实际订票数 SELECT COUNT(*) FROM BOOKING WHERE flight_no CA123; -- 查看状态为CONFIRMED的订单数 SELECT COUNT(*) FROM BOOKING WHERE flight_no CA123 AND status CONFIRMED;理想结果available_seats≥ 0且COUNT(*)等于初始余票数如初始10张则COUNT10。若available_seats为负说明事务控制失效若COUNT小于初始值说明部分请求因余票不足被拒绝——这正是正确行为。6.3 进阶技巧用Oracle V$SESSION_LONGOPS监控慢SQL当压力测试响应变慢时别急着优化Java代码。先查Oracle是否在执行慢操作SELECT sid, serial#, opname, target, sofar, totalwork, ROUND(sofar/totalwork*100, 2) AS progress_pct FROM v$session_longops WHERE opname LIKE %UPDATE% AND sofar totalwork;如果看到opnameUPDATE且progress_pct长期卡在99%说明UPDATE被阻塞——大概率是某个会话未提交事务持有了行锁。此时用SELECT blocking_session, sql_id, event FROM v$session WHERE blocking_session IS NOT NULL;找到阻塞者SID再杀掉它ALTER SYSTEM KILL SESSION sid,serial# IMMEDIATE;我带学生做课设时总强调一件事数据库课程设计的终点不是PDF里那张ER图而是你亲手让SELECT available_seats FROM FLIGHT这个数字在100次并发后依然坚挺地停在0——不多不少不增不减。那个瞬间你才真正摸到了事务、锁、隔离级别的脉搏。后面所有框架、ORM、云数据库都不过是这个内核的包装纸。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。