数据库上机实验2~3
实验2,3
最重要的提醒!
如果你正开始写或者写了一半了,请务必牢记下面三点。
- 如果你传参的时候传了
connection
或是statement
,不能在这个函数里close
,不然你的主函数里就没法用了; - 每一个
statement
都最好只对应一个SQL
语句(不然你可能在半途把stmt.close()
)后面就不能使用了 - 最好用的工具
try-catch(Exception e){e.printStackTrace();}
可以快速定位到是哪里错了以及错误的原因;
血泪经验总结。然后,如果你还没开始写JDBC
,建议去写MyBatis
。
一、实验要求
基于MySQL,设计并实现一个简单的旅行预订系统。该系统涉及的信息有航班、大巴班车、宾馆房间和客户数据等信息。其关系模式如下:
FLIGHTS (
String flightNum
, int price, int numSeats, int numAvail, String FromCity, String ArivCity);
HOTELS(String location
, int price, int numRooms, int numAvail);
BUS(String location
, int price, int numBus, int numAvail);
CUSTOMERS(String custName
,custID);
RESERVATIONS(String custName, int resvType,String resvKey
) ;
为简单起见,对所实现的应用系统作下列假设:
- 在给定的一个班机上,所有的座位价格也一样;
flightNum
是表FLIGHTS
的一个主码(primary key)
。 - 在同一个地方的所有的宾馆房间价格也一样;
location
是表HOTELS
的一个主码。 - 在同一个地方的所有大巴车价格一样;
location
是表BUS
的一个主码。 custName
是表CUSTOMERS
的一个主码。- 表
RESERVATIONS
包含着那些和客户预订的航班、大巴车或宾馆房间相应的条目,具体的说,resvType
指出预订的类型(1为预订航班,2为预订宾馆房间,3为预订大巴车),而resvKey
是表RESERVATIONS
的一个主码。(这句话怎么理解?) - 在表
FLIGHTS
中,numAvail
表示指定航班上的还可以被预订的座位数。对于一个给定的航班(flightNum)
,数据库一致性的条件之一是,表RESERVATIONS
中所有预订该航班的条目数加上该航班的剩余座位数必须等于该航班上总的座位数。这个条件对于表BUS
和表HOTELS
同样适用。
客户的名字竟是主码,是唯一不重复的;那么他的ID有什么用?身份证号吗?(暂且就这样吧);Bus、Hotel在某一
location
下只能有一家(主码约束)。【关于
reservation
的分析】for
resvKey
:与cust_name
、resv_type
合起来是reseveration
的主码。
应用系统应完成如下基本功能:
- 航班,大巴车,宾馆房间和客户基础数据的入库,更新(表中的属性也可以根据你的需要添加)。
- 预定航班,大巴车,宾馆房间。
- 查询航班,大巴车,宾馆房间,客户和预订信息。
- 查询某个客户的旅行线路。
- 检查预定线路的完整性。
- 其他任意你愿意加上的功能。
二、关于数据约束的讨论
1.完整性约束
对于
reservation
中的resvType
取值只有:1,2,3。因此对于所有的reservation
记录的resvType
,若其值>3,那么该记录就不应存在。constraint limType check ( resvType>0 and resvType<4)
对于
reservation,bus,hotel
:numXxx=numAvail+resveration中的记录条数
对于
flight
中的FromCity
不能等于ArivCity
。
2.主码约束
- FLIGHTS (String flightNum, int price, int numSeats, int numAvail, String FromCity, String ArivCity);
- HOTELS(String location, int price, int numRooms, int numAvail);
- BUS(String location, int price, int numBus, int numAvail);
- CUSTOMERS(String custName,custID);
- RESERVATIONS(String custName, int resvType, String resvKey) ;
- 对于不同的航班来说,该航班号是唯一的。
- 对于同一
location
下,只能存在一家hotel
记录。- 对于同一
location
下,只能存在一家bus
记录。- 每位
customer
的名字custName
一定是不同的。- 对
reseverations
来说,其元素为resv_type,resv_key,cust_name
,三者均可重复,但是三者组合起来作为serveration
的主键,是唯一不重复的。
三、程序实现
1.实现功能
main
函数要实现的功能:
1.添加fight,bus,hotel,customer
数据-入库
2.添加reservation
数据-入库-<会相应地变更其他数据库的内容,事务>
3.查询所有的数据-一键查询所有的数据?还是分开来写?
4.查询某用户的旅行路线–什么是旅行路线?指订的航班、酒店、大巴酱?
5.检查【预定线路】的完整性?–用户已预定,然后两地之间存在航班。
功能①:基本的增删改操作(for flight,bus,hotel,customer)
insert:好坑,就是使用PreparedStatement
的时候,已经建立好sql
语句后,应使用pstmt.executeUpdate()
注意括号内无sql参数!
1 | sql="insert into flights values(?,?,?,?,?)"; |
update
1 | sql="update flights set price=?," + |
delete
1 | sql="delete from flights where flight_num=?" |
功能②:基本的增删改操作(for reseveration)
预订航班、大巴车、宾馆房间。采用事务,原子性操作!
操作流程:
- 将事务自动提交设置为
false
- 先更改用户指定的预订的对应航班、大巴车、宾馆表的数据(
num_avail
变更); - 添加一条预订记录:正常在预订中insert数据。
- 操作成功:事务提交;
- 操作失败:事务回滚。
功能③:查询操作
就是显示数据,是十分简单的操作。
功能④:查某用户的旅行路线
操作流程:
- 找到对应用户的
reservations
的信息,其中可能包括flight,hotel,bus
的相关信息。 - 分别对三者进行查询并归入
list
。 - 分别打印输出。
功能⑤:检查预定线路的完整性
对于题意的理解:对于特定的用户(给定用户的cust_name
),查询其航班信息是否真实存在,即在flights
表中找到相应的航班信息。
实现:在实现功能②向reservations
中插入预订信息之前,首先需要对操作者输入的信息进行检查(是否在相应的表中存在数据)
2.扩展功能
操作者可能输入错误的数据,对于错误的数据会进入数据库中进行操作:
- 对于该部分采用了异常处理,用户输入错误的信息并不会导致程序抛出异常而错误退出;而是由我进行异常的捕获并进行处理,并提醒用户输入了错误的信息。
之后可以进行扩展:
- 每一班的航班应当具有起飞时间-到达时间的信息;在超过了该预订日期之后会自动更新航班信息为新的日期以及全部可预订的座位;
- 对于查询表格的信息,此处是以
List
形式打印;可以使用Java API
中封装好的一些类进行优化; - 使用
MyBatis
(已封装)而不是JDBC
(未封装,且易出现SQL注入问题)
四、功能验证
功能①
insert
update
记录一下:当时出现错误,就是PreparedStatement
的sql
语句去给占位符赋值时搞错了顺序。然后很扯的事情来了,就是java会延迟,更新程序的部分并不能及时载入。(之前也这样过,得亏我想起来了)
delete
功能②
insert
update
感觉没什么用处,因此不考虑这个的实现。