数据库实验八数据库编程.docx
《数据库实验八数据库编程.docx》由会员分享,可在线阅读,更多相关《数据库实验八数据库编程.docx(12页珍藏版)》请在冰豆网上搜索。
数据库实验八数据库编程
河南工业大学实验报告
课程数据库系统原理及应用实验名称实验八、简单数据库应用系统开发
院系信息科学与工程学院指导老师:
孙宜贵日期2016.11.28
专业班级计科F1401姓名郑旺旺学号201416010102
一.实验目的
1、理解数据库驱动的应用系统的工作原理,熟悉数据库应用系统的基本开发流程;
2、采用自己熟悉的开发平台(如Java)、编程语言(如Java)和数据库访问技术(如JDBC),结合SQLSERVER数据库实现一个典型的基于数据库的应用程序(Web应用程序、桌面应用、移动应用等均可),深刻理解数据库在系统中的地位,培养系统思维。
二.实验要求
1.在《数据库设计》和《数据库编程》实验的基础上,实现目标系统业务需求所规定的主要内容,构建一个可运行的数据库应用系统,并整理相应文档,提交实验报告。
2.最低要求:
在应用程序的相应模块中通过JDBC调用《数据库编程》实验内容1~4中实现的存储过程;
3.扩展要求:
个人在《数据库编程》实验内容5中列出的其他各项数据库访问操作(数据添加、修改、删除、查看或统计)的数据库代码必须封装为存储过程,然后在应用程序中通过JDBC调用存储过程。
4.说明:
不得采用Hibernate等ORM组件;对于应用程序的外观设计和其他框架组件(如Struts、Spring、Swing等)不做限制;有明显抄袭痕迹、雷同者本次成绩作废。
三.实验内容
内容提纲:
1)整体实现思想、方案等描述;
2)模块(或子系统)设计与实现(各个模块要分开按序填写!
)
(主要包括运行界面截图、对应存储过程脚本、调用代码、界面逻辑处理代码等体现个人工作的内容。
)
说明:
截图精简、注释适当,尽量去除无关代码;对应用程序设计方案的图形化表示不做要求,如果绘图请采用一致的方法。
四.实验过程及结果
1)系统实现思想及方案
本系统采用JDBC链接数据库,通过JDBC调用数据库中已经实现的存储过程,实现增,删,改,查及其他操作。
系统分为六个模块,分别调用相应的存储过程实现相应的功能。
主要实现方案如下:
用户通过JSP和与系统交互,Servlet得到用户的请求,调用Service中的方法,Dao层根据service层的需求来调用相应的存储过程,并把存储过程中数据中执行的结果存储到集合中在逐层传递给用户。
其中,DAO层中使用c3p0连接池来统一管理连接,这样做的好处是不用每次操作数据库都需要创建连接,而是使用连接池提供的连接,使用之后再重新归还给连接池,这样达到了连接复用的效果,提升了软件的性能。
2)模块设计与实现
系统主界面:
子模块1:
调用存储过程增加单条记录
运行截图:
存储过程脚本:
createprocedureInsertOneRecord
@IDint,
@FirstNamevarchar(20),
@LastNamevarchar(20),
@Phonevarchar(11),
@Emailvarchar(20)
as
insertintoCustomer
values(
@id,
@FirstName,
@LastName,
@Phone,
@Email)
go
调用代码:
publicstaticvoidexecuteAdd(Customerc)throwsSQLException{
QueryRunnerqr=newTxQueryRunner();
Stringsql="{callInsertOneRecord(?
?
?
?
?
)}";
Object[]params={c.getID(),c.getFirstName(),c.getLastName(),c.getPhone(),c.getEmail()}
qr.update(sql,params);
}
子模块2:
调用存储过程修改单条记录
运行截图:
存储过程脚本:
createprocedureUpdateOneRecord
@IDint,
@FirstNamevarchar(20),
@LastNamevarchar(20),
@Phonevarchar(11),
@Emailvarchar(20)
as
updateCustomer
set
FirstName=@FirstName,
LastName=@LastName,
Phone=@Phone,
Email=@Email
whereCustomerID=@id
go
调用代码:
publicstaticvoidexecuteUpdate(Customerc)throwsSQLException{
QueryRunnerqr=newTxQueryRunner();
Stringsql="{callUpdateOneRecord(?
?
?
?
?
)}";
Object[]params={c.getID(),c.getFirstName(),c.getLastName(),c.getPhone(),c.getEmail()}
qr.update(sql,params);
}
子模块3:
调用存储过程删除单条记录
运行截图:
存储过程脚本:
createprocedureDeleteOneRecord
@IDint
as
deleteCustomer
whereCustomerID=@ID
go
调用代码:
publicstaticvoidexecuteDelete(intID)throwsSQLException{
QueryRunnerqr=newTxQueryRunner();
Stringsql="{callDeleteOneRecord(?
)}";
qr.update(sql,ID);
}
子模块4:
调用存储过程查看顾客
运行截图:
存储过程脚本:
createprocedureShowRecord
as
select*fromCustomer;
go
调用代码:
publicstaticListexecuteShow()throwsSQLException{
QueryRunnerqr=newTxQueryRunner();
Stringsql="{callShowRecord}";
ListallList=qr.query(sql,newBeanListHandler(Customer.class));
returnallList;
}
子模块5:
调用存储过程查询在指定时间段内销售订单统计数据
运行截图:
存储过程脚本:
createprocedureQueryData
@sdatedate,
@edatedate
as
selectC.CustomerID,N.全名,Phone,T.订单个数,T.税后总金额
fromCustomerC,
(select
CustomerID,count(SaleID)as'订单个数',
sum(Price*(1-Tax))as'税后总金额'
fromSales
whereSaleDatebetween@sdateand@edate
groupbyCustomerID)T,
(selectdbo.GetName(CustomerID)as全名,CustomerID
fromCustomer
)N--调用函数生成含有全名的临时表
whereC.CustomerID=T.CustomerIDandT.CustomerID=N.CustomerID
orderbyT.订单个数desc,N.全名asc
go
调用代码:
publicstaticListexecuteSalesData(Stringsdate,Stringedate)throwsSQLException,ParseException{
QueryRunnerqr=newTxQueryRunner();
Stringsql="{callQueryData(?
?
)}";
java.util.Datesddate=newSimpleDateFormat("yyyy/MM/dd").parse(sdate);
java.sql.DatesqlsDate=newjava.sql.Date(sddate.getTime());
java.util.Dateeddate=newSimpleDateFormat("yyyy/MM/dd").parse(edate);
java.sql.DatesqleDate=newjava.sql.Date(sddate.getTime());
params={sqlsDate,sqleDate}
ListallList=qr.query(sql,newBeanListHandler(SalesOrder.class),params);
returnallList;
}
子模块6:
调用存储过程将指定日期之前进的货进行按指定折扣打折处理
运行截图:
存储过程脚本:
createprocedureDiscount
@Datedate
as
selectP.ProductID,PName,P.Priceas'原价',D.折后价,PurchaseDate
fromProductP,
(selectProductID,Price*0.7as'折后价'
fromProduct
wherePurchaseDate<@Date)D
whereP.ProductID=D.ProductID
go
调用代码:
publicstaticListexecuteDiscount(Stringdate)throwsSQLException,ParseException{
QueryRunnerqr=newTxQueryRunner();
Stringsql="{callDiscount(?
)}";
java.util.Dateudate=newSimpleDateFormat("yyyy/MM/dd").parse(date);
java.sql.DatesqlDate=newjava.sql.Date(udate.getTime());
Object[]param={sqlDate};
returnqr.query(sql,newBeanHandler(Product.class),param);
}
五.实验中的问题及心得
这次实验是对上次实验的代码化,使用jdbc来调用数据库的存储过程。
实验中运用了连接池来管理连接,达到连接的复用性,提高了软件的性能。
在学习存储过程之前我只会对数据库进行最基本的增、删、改、查操作,一些业务完全是依靠于数据库的基本操作来完成的,学习过存储过程和自定义函数之后,发现业务可以放在数据库中来实现,这样做的好处就是减少对数据库的访问次数,从而达到代码的优化。
在实验的过程中使用了commons组件中的dbutils,但是调用存储过程在Java中使用的是CallableStatement接口,而QueryRunner类中使用的是PrepareStatement接口,这样做会不会出现问题呢?
于是我就查看了JavaSE的帮助文档,发现CallableStatement是PrepareStatement的子接口,但是CallableStatement接口中并没有execute()方法和executeQuery()方法,也就是说这两个方法是父接口的,而且里面的设置参数的方法也是父接口的,这样的话基本上可以用父接口PrepareStatement替代了。
所以QueryRunner类还是可以使用的。
实验中用了自己写的JdbcUtils工具类来管理连接连接池中的连接,而且自己写了TxQueryRunner类来包装父类,这个类重写了父类QueryRunner中所有无Connection参数的方法,然后调用父类的有Connection参数的重载方法,其中Connection通过自己写的JdbcUtils工具类来获取连接。
这样做的话对数据库的操作只需要提供sql语句的模板和参数即可,不需要考虑连接的问题,代码量大大的减少。