JSP—JSP中使用数据库

目录

前言

8.1MySQL数据库管理系统

8.1.1 下载、安装MySQL

8.1.2  启动MySQL数据库服务器

8.1.3  MySQL客户端管理工具

8.2连接MySQL数据库

8.3.1 结果集与查询

8.3.2 随机查询

8.3.3 条件查询

8.4更新、添加与删除记录

8.5用结果集操作数据库中的表

8.6预处理语句

8.6.1 预处理语句优点

8.6.2 使用通配符

8.7事务

8.8分页显示记录

8.9连接SQL Server与Access数据库

8.9.1 连接Microsoft SQL Server数据库

8.9.2 连接Microsoft Access数据库

8.10使用连接池

8.10.1 连接池简介

8.10.2 建立连接池

8.11标准化考试训练

8.11.1 功能概述

8.11.2 数据库设计


前言

        JSP可以使用Java中的JDBC API来访问数据库。

8.1MySQL数据库管理系统

MySQL数据库管理系统,简称MySQL,是目前流行的开源数据库管理系统,其社区版(MySQL Community Edition)是可免费下载的开源数据库管理系统。MySQL最初由瑞典MySQL AB公司开发,目前由Oracle公司负责源代码的维护和升级。Oracle将MySQL分为社区版和商业版,并保留MySQL开放源码这一特点。目前许多Web开发项目都选用社区版MySQL,其主要原因是社区版MySQL的性能卓越,满足许多Web应用已经绰绰有余,而且社区版MySQL是开源数据库管理系统,可以降低软件的开发和使用成本。

8.1.1 下载、安装MySQL

1.下载

https://dev.mysql.com/downloads/mysql/

选择Windows (x86, 64-bit), ZIP Archive 8.0.18(272.3M) 这里我们下载的是mysql-8.0.18-winx64.zip(适合64位机器的Windows版)。

2.安装

将下载的mysql-8.0.18-winx64.zip解压缩到本地计算机,比如解压缩到D:\。本教材将下载的mysql-8.0.18-winx64.zip解压缩到D:\

8.1.2  启动MySQL数据库服务器

1.启动

■(安全初始化)首次启动之前必须进行安全初始化(以管理员身份启动命令行窗口).使用命令行进入MySQL安装目录的bin子目录,键入 mysqld --initialize-insecure命令,回车确认.

D:\mysql-8.0.18-winx64\bin>mysqld  --initialize-insecure

初始化后,必须用管理员身份(在cmd.exe上单击鼠标右键,选择以管理员身份运行cmd)启动命令行窗口,然后进入MySQL安装目录的bin子目录下键入mysqld或 mysqld -nt ,回车确认启动MySQL数据库服务器(以后再启动MySQL就不要再初始化了,以免引起系统混乱),MySQL服务器占用的端口是3306(3306是MySQL服务器默认使用的端口号)。启动成功后(无任何提示信息),MySQL数据库服务器将占用当前MS-DOS窗口

2.root用户

MySQL8.0版本必须对root用户进行身份确认,否则将导致MySQL 8.0自带的mysql客户端程序,以及其他的客户端程序,如Navicat for MySQL等无法访问MySQL 8.0数据库服务器。 再用管理员身份打开另一个命令行窗口(在cmd.exe上单击鼠标右键,选择以管理员身份运行cmd)

D:\mysql-8.0.18-winx64\bin>mysqladmin  -u root -p  password 

回车确认后,将提示输入root的当前密码(无密码就直接回车确认,初始是无密码),如果输入正确,将继续提示输入root的新密码(如果新密码仍然保持是无密码,就直接回车确认),以及确认新密码。

8.1.3  MySQL客户端管理工具

所谓MySQL客户端管理工具,就是专门让客户端在MySQL服务器上建立数据库的软件。可以下载图形用户界面(GUI)的MySQL管理工具,并使用该工具在MySQL服务器上进行创建数据库、在数据库中创建表等操作,MySQL管理工具有免费的也有需要购买的。例如Navicat for MySQL,登录: http://www.navicat.com.cn/download 下载试用版或购买商业版,例如下载navicat121_mysql_cs_x64.exe,安装即可。

1.命令行客户端

打开一个新的命令行窗口(不必管理员身份),进入MySQL安装目录下的bin子目录。运行mysql:

mysql -h ip -u root -p

对于本机调试(即客户端和数据库服务器同机),执行格式为:

mysql  -u root -p

然后按要求输入密码即可(如果密码是空,可以不输入密码)。

 启动命令行客户端后就可以使用SQL语句进行创建数据库、建表等操作。在MS-DOS命令行窗口输入SQL语句需要用“;”号结束,在编辑SQL语句的过程中可以使用\c终止当前SQL语句的编辑。需要提醒的是,可以把一个完整的SQL语句命令分成几行来输入,最后用分号作结束标志即可。

2. 创建数据库

创建一个名字为bookDatabase的数据库

create database bookDatabase;

 删除已有数据库:

drop database bookDatabase;

3.建表

为了在数据库中创建表,必须首先进入该数据库(即使用数据库),命令格式是:“user 数据库名;”或“user 数据库名”。在当前命令行客户端管理工具占用的命令行窗口输入:

use  bookDatabase

回车确认(进入数据库也可以没有分号)进入数据库bookDatabase

 创建bookList表:

create table bookList(

ISBN varchar(100) not null,

name varchar(100) character set gb2312, price float,

publishDate date,

primary key(ISBN)

);

 创建bookList表之后就可以使用SQL语句对bookList表进行添加、更新和查询等操作(如果已经退出数据库,需要再次进入数据库)。在当前命令行客户端占用的窗口键入插入记录的SQL语句(如图8.10所示。),记录之间用逗号分隔:

insert into bookList values('7302014655','高等数学',28.67,'2020-12-10'),

('7352014658','大学英语',58.5,'1999-9-10'),

('7987302464259','Java2实用教程第5版',59.5,'2017-5-1');

 

 4.导入.sql文件中的SQL语句

在使用命令行客户端时,如果觉得在命令行输入SQL语句不方便,那么可以事先将需要的SQL语句保存在一个扩展名是.sql的文本文件中,然后在命令行客户端占用的命令行窗口使用source命令导入.sql文件中的SQL语句。a.sql如下:

insert into bookList values('8302084658','月亮湾',38.67,'2021-12-10'),

('9352914657','雨后',78,'1998-5-19'),

('9787302198048','Java设计模式',29,'1999-5-16'),

('97873902488644','Java课程设计第3版',32,'2018-1-10');

select * from bookList;

在当前命令行客户端占用的窗口键入如下命令: source D:/myFile/a.sql 回车确认,导入sql文件中的SQL语句。

如果a.sql文件中存在错误的SQL语句,将提示错误信息,否则将成功执行这些SQL语句

 5. 删除数据库或表

删除数据库的命令:drop database <数据库名>,例如:删除名为tiger的数据库:

drop database tiger;

删除表的命令:drop table <表名>,例如,使用bookDatabase数据库后,执行:

drop table booklist;

将删除bookDatabase数据库中的bookList表。

6.使用 Navicat for MySQL

登录:http://www.navicat.com.cn/download下载试用版或购买商业版,例如下载试用版navicat121_mysql_cs_x64.exe

8.2连接MySQL数据库

为了使Java编写的程序不依赖于具体的数据库,Java提供了专门用于操作数据库的API,即JDBC(Java Data Base Connectivity)。JDBC操作不同的数据库仅仅是加载的数据库连接器不同以及和数据库建立连接的方式不同而已,使用JDBC的应用程序和数据库建立连接之后,就可以使用JDBC提供的API操作数据库。

1.下载JDBC-MySQL数据库连接器表

https://dev.mysql.com/downloads/connector/j/

下载的是mysql-connector-java-8.0.18.zip(linux系统可下载tar.gz格式文件),将该zip文件解压至硬盘,在解压目录下的mysql-connector-java-8.0.18.jar文件就是连接MySQL数据库的JDBC-MySQL数据库连接器(作者也将该文件放在了教学资源的源代码文件夹中)。

■将MySQL数据库的JDBC-MySQL数据库连接器

mysql-connector-java-8.0.18.jar

保存到Tomcat安装目录下的lib文件夹中(例如D:\apache-tomcat-9.0.26\lib).

重新启动Tomcat服务器。

2.加载JDBC-MySQL数据库连接器

try{  Class.forName("com.mysql.cj.jdbc.Driver ");

}

catch(Exception e){}

MySQL数据库驱动是mysql-connector-java-8.0.18.jar文件中的Driver类,该类的包名是com.mysql.cj.jdbc.Driver(包名和以前的版本: com.mysql.jdbc.Driver不同)。Driver类不是Java运行环境类库中的类,是连接器mysql-connector-java-8.0.18.jar中的类

JDBC操作不同的数据库仅仅是加载的数据库连接器不同以及和数据库建立连接的方式不同而已,使用JDBC的应用程序和数据库建立连接之后,就可以使用JDBC提供的API操作数据库。

 3.连接数据库

Connection con;

String url =

"jdbc:mysql://192.168.100.1:3306/bookDatabase?useSSL=false&serverTimezone=GMT";

String user ="root";

String password ="";

try{        

con = DriverManager.getConnection(url,user,password); //连接代码

} catch(SQLException e){      

System.out.println(e);

}

4.注意汉字问题

需要特别注意的是,如果数据库的表中的记录有汉字,那么在建立连接时需要额外多传递一个参数characterEncoding,并取值gb2312或utf-8

String url =

"jdbc:mysql://localhost/bookDatabase?"+ "useSSL=false&serverTimezone=GMT&characterEncoding=utf-8";

con = DriverManager.getConnection(url, "root","");

8.3查询记录

和数据库建立连接后,就可以使用JDBC提供的API与数据库交互信息,比如查询、修改和更新数据库中的表等。JDBC与数据库表进行交互的主要方式是使用SQL语句(其他方式见8.5节)。JDBC提供的API可以将标准的SQL语句发送给数据库,实现和数据库的交互。

8.3.1 结果集与查询

对一个数据库中的表进行查询,然后将查询结果返回到一个ResultSet对象中,习惯称ResultSet对象为结果集对象。SQL查询语句与结果集 连接对象con调用方法createStatement()返回SQL语句对象,代码如下:

try{ Statement sql=con.createStatement();  

 }

catch(SQLException e ){      

System.out.println(e);

}

■结果集 sql对象就可以调用相应的方法查询数据库中的表,并将查询结果存放在一个ResultSet结果集中。ResultSet结果集由以列(也称字段)为结构的数据行组成。例如,对于

ResultSet rs=sql.executeQuery("SELECT * FROM bookList");

内存中的结果集对象rs的列数是4列,刚好和bookList表的列数相同,第1列至第4列分别是ISBN、name、price和publishDate列;而对于

ResultSet rs=sql.executeQuery("SELECT name,price FROM bookList");

结果集对象rs只有两列,第1列是name列,第2列是price列。

■ResultSet结果集一次只能看到一个数据行,使用next()方法可走到下一数据行。获得一行数据后,ResultSet结果集可以使用getXxx(int columnIndex)或getXxx(String columnName)方法获得字段值(列值)

无论列(字段)是何种属性,总可以使用getString(int columnIndex)或getString(String columnName)方法返回列(字段)值的串表示。

8.3.2 随机查询

默认的ResultSet结果集使用next()方法顺序地查询记录,但有时候需要在结果集中前后移动、显示结果集指定的一条(一行)记录或随机显示若干条记录等。这时,必须返回一个可滚动的结果集(结果集的游标可以上下移动)。

Statement stmt=con.createStatement(int type,int concurrency);  

 ResultSet re=stmt.executeQuery(SQL语句);

type:    

ResultSet.TYPE_FORWORD_ONLY  

 ResultSet.TYPE_SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变。

ResultSet.TYPE_SCROLL_SENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集同步改变。

Concurrency:  

ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。   ResultSet.CONCUR_UPDATABLE:能用结果集更新数据库中的表。

8.3.3 条件查询

1. where子语句

一般格式:  

select 字段 from 表名 where 条件

(1)字段值和固定值比较,例如:

select name,price from bookList where name='高等数学'

(2)字段值在某个区间范围,例如:

select * from bookList where price>28.68 and price<=87.7

select * from bookList where price>56 and name != '月亮湾'

使用某些特殊的日期函数,如year,month,day:

select * from bookList where year(publishDay)<1980

select * from bookList where year(publishDay) between 2015 and 2020

(3)用操作符like进行模式般配,使用%代替0个或多个字符,用一个下划线_代替一个字符。例如查询name含有“程序”二字的记录:  

select * from bookLidt where name like '%程序%'

2. 排序

用order by子语句对记录排序,

select * from 表名 order by 字段名(列名)

select * from 表名 where 条件 order by 字段名(列名)

例如:

select * from bookList order by price

select * from bookList where name like '%编程%' order by name

将例子8_1中的查询bookList表中SQL语句:

String SQL = "SELECT * FROM bookList";

替换成:

String SQL="select * from bookList "+      

         "where year(publishDate) between 1999 and 2021 and price>=30 "+    

            " order by publishDate";

8.4更新、添加与删除记录

 public int executeUpdate(String sqlStatement);

通过参数sqlStatement指定的方式实现对数据库表中记录的更新、添加和删除操作

1.更新

update  表 set 字段 = 新值 where <条件子句>  

update bookList set publishDate = '2019-12-26' where name='大学英语'

例如:

sql.executeUpdate

("update bookList set publishDate ='2019-12-26' where name='大学英语'");

2.添加

insert into 表(字段列表) values (对应的具体的记录)

insert into 表 values (对应的具体的记录)

insert into bookList values ('2306084657','春天', 35.8,'2020-3-20'),                             ('5777564629','冬日', 29.9,'2019-12-23')

3.删除

delete from  表名 where <条件子句> delete  from bookList where ISBN = '9352914657'

8.5用结果集操作数据库中的表

■更新记录

步骤:

1)游标移动到第n行:

        rs.absolute(n);

(2)结果集rs将第n行的column列的列值更新。

        rs.updateDate(int column, Date x);

(3)更新数据库中的表。最后,结果集rs调用updateRow()方法用结果集中的第n行更新数据库表中的第n行记录。

rs.updateRow();

例如:

        rs.absolute(3);

        rs.updateString(2, "操作系统");

        rs.updateRow();

■插入记录

步骤:

(1)将结果集rs的游标移动到插入行。

         rs.moveToInsertRow();

(2)更新插入行的列值。设置插入行的列值:

         rs.updateString(1, "7307014659");

         rs.updateString(2, "数据结构");

        rs.updateFloat(3,58);

        rs.updateDate(4, '2020-08-10');

(3) 最后,结果集调用insertRow()方法用结果集中的插入行向数据库表中插入一行新记录:

   rs.insertRow()

8.6预处理语句

Java提供了更高效率的数据库操作机制,就是PreparedStatement对象。

8.6.1 预处理语句优点

减轻数据库的负担,也提高了访问数据库的速度。

■ 步骤

1.  Connection连接对象con调用prepareStatement(String sql)方法:

   PreparedStatement pre=con.prepareStatement(String sql);

对参数sql指定的SQL语句进行预编译处理,生成该数据库底层的内部命令,并将该命令封装在PreparedStatement对象pre中。

2. pre对象调用下列方法都可以使得该底层内部命令被数据库执行:

ResultSet executeQuery()

boolean execute() (执行成功返回false)

int executeUpdate() (执行成功返回1)

只要编译好了PreparedStatement对象pre,那么pre可以随时执行上述方法,显然提高了访问数据库的速度。

8.6.2 使用通配符

在对SQL进行预处理时可以使用通配符?(英文问号)来代替字段的值,只要在预处理语句执行之前再设置通配符所表示的具体值即可。例如:

pre=con.prepareStatement("SELECT * FROM bookList WHERE price < ? ");

在sql对象执行之前,必须调用相应的方法设置通配符?代表的具体值,比如:

pre.setFloat(1,65);

指定上述预处理语句pre中通配符?代表的值是65。通配符按照它们在预处理的“SQL语句”中从左至右依次出现的顺序分别被称作第1个、第2个…… 第m个通配符。

8.7事务

1.事务

事务由一组SQL语句组成。所谓“事务处理”是指应用程序保证事务中的SQL语句要么全部都执行,要么一个都不执行。

2.事务处理

事务处理是保证数据库中数据完整性与一致性的重要机制。应用程序和数据库建立连接之后,可能使用多条SQL语句操作数据库中的一个表或多个表。一个管理资金转账的应用程序为了完成一个简单的转账业务可能需要两条SQL语句,比如,有户geng给另一个用户zhang转帐50元,那么需要一条SQL语句完成将用户geng的userMoney的值由原来的100更改为50(减去50的操作),另一条SQL语句完成将zhang的用户的userMoney的值由原来的20更新为70(增加50的操作)。应用程序必须保证这两条SQL语句要么全都执行,要么全都不执行。

3.事务处理步骤

1)用setAutoCommit(booean b)方法关闭自动提交模式  

 con.setAutoCommit(false);

2)用commit()方法处理事务                  

 con.commit();  

Statement对象(PreparedStatement对象)提交多个SQL语句,这些SQL语句就是一个事务。事务中的SQL语句不会立刻生效,直到连接con调用commit()方法。

3)用rollback()方法处理事务失败  

con.rollback();

连接con调用commit()方法进行事务处理时,只要事务中任何一个SQL语句没有生效,就抛出SQLException异常。在处理SQLException异常时,必须让con调用rollback()方法,其作用是:撤消事务中成功执行过的SQL语句对数据库数据所做的更新、插入或删除操作,即撤消引起数据发生变化的SQL语句操作,将数据库中的数据恢复到commit()方法执行之前的状态。

8.8分页显示记录

可以使用二维数组table存放表的记录,即用二维数组table中的行(一维数组table[i])存放一条记录。

如果一个表中有许多记录,那么二维数组table就有多行。

为避免长时间占用数据库的连接,应当将全部记录存放到二维数组中,然后关闭数据库连接。

假设table存放了m行记录,准备每页显示n行,那么,总页数的计算公式是:

●如果m除以n的余数大于0,总页数等于m除以n的商加1;

●如果m除以n的余数等于0,总页数等于m除以n的商。

总页数=(m%n)==0?(m/n):(m/n+1);

●如果准备显示第p页的内容,应当从table第(p-1)*n行开始,连续输出n行(最后一页可能不足n行)。

本节例子8_8使用MVC模式(有关知识见第7章)用分页的方式显示记录。

例子8_8

1.bean(模型)

Record_Bean.java(负责创建session bean)

package save.data;
public class Record_Bean{
   String []columnName ;           //存放列名。
   String [][] tableRecord=null;   //存放查询到的记录。
   int pageSize=3;                 //每页显示的记录数。
   int totalPages=1;               //分页后的总页数。
   int currentPage =1   ;          //当前显示页 。
   int totalRecords ;             //全部记录。
   public void setTableRecord(String [][] s){
      tableRecord=s;
   }
   public String [][] getTableRecord(){
      return tableRecord;
   }
   public void setColumnName(String [] s) {
      columnName = s;
   }
   public String [] getColumnName() {
      return columnName;
   }
   public void setPageSize(int size){
      pageSize=size;
   }
   public int getPageSize(){
      return pageSize;
   } 
   public int getTotalPages(){
      return totalPages;
   } 
   public void setTotalPages(int n){
      totalPages=n; 
   }
   public void setCurrentPage(int n){
      currentPage =n;
   }
   public int getCurrentPage(){
      return currentPage ;
   }
    public int getTotalRecords(){
      totalRecords = tableRecord.length;
      return totalRecords ;
   }
}

bean的id是recordList,是session bean,用于存储从数据库的表中查询到的记录。

用命令行进入save\data的父目录classes,编译Record_Bean.java(见本章开始的约定):

classes> javac  save\data\BookList_Bean.java

2.JSP页面(视图)

视图部分由两个JSP页面构成,其中example8_8_input.jsp页面负责提供输入数据的视图,即用户可以在该页面输入数据库的名、表名、密码等信息,然后提交给名字是query的servlet。query负责查询数据库,并将结果存储到id为recordBean的session bean中,然后请求视图中的example8_8_show.jsp页面显示recordBean的数据(分页显示)。

example8_8_input.jsp

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %>
<style>
   #tom{
      font-family:宋体;font-size:26;color:blue 
   }
</style>
<HTML><body bgcolor=#ffccff>
<form action="query" id=tom method=post>
<b>数据库<input type='text' id=tom name='dataBase' value ='bookDatabase'/>
<br>表名<input type='text' id=tom name='tableName' value='bookList'/>
<br>用户名(默认root)<input type='text' id=tom name='user' value='root'/>
<br>用户密码(默认空)<input type='text'id=tom name='password'/>
<br><input type='submit' name='submit' id=tom value='提交'>
</form>
</body></HTML>  

example8_8_show.jsp

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %>
<style>
   #tom{
      font-family:宋体;font-size:26;color:blue 
   }
</style>
<jsp:useBean id="recordBean" class="save.data.Record_Bean" scope="session"/>
<HTML><body bgcolor=#9FEFDF><center>
<jsp:setProperty name="recordBean" property="pageSize" param="pageSize"/>
<jsp:setProperty name="recordBean" property="currentPage" param="currentPage"/>
</p>
<table id =tom border=1>
<%
    String [][] table=recordBean.getTableRecord();
    if(table==null) {
       out.print("没有记录");
       return;
    }
    String []columnName=recordBean.getColumnName();
    if(columnName!=null) { 
        out.print("<tr>");
        for(int i=0;i<columnName.length;i++){
           out.print("<th>"+columnName[i]+"</th>");
        }
        out.print("</tr>");
    } 
    int totalRecord = table.length;
    int pageSize=recordBean.getPageSize();  //每页显示的记录数
    int totalPages = recordBean.getTotalPages();
    if(totalRecord%pageSize==0)
         totalPages = totalRecord/pageSize;//总页数
    else
         totalPages = totalRecord/pageSize+1;
    recordBean.setPageSize(pageSize);
    recordBean.setTotalPages(totalPages);
    if(totalPages>=1) {
         if(recordBean.getCurrentPage()<1)
             recordBean.setCurrentPage(recordBean.getTotalPages());
         if(recordBean.getCurrentPage()>recordBean.getTotalPages())
             recordBean.setCurrentPage(1);
         int index=(recordBean.getCurrentPage()-1)*pageSize;
         int start=index;  //table的currentPage页起始位置。
         for(int i=index;i<pageSize+index;i++) { 
            if(i==totalRecord)
               break;
            out.print("<tr>");
            for(int j=0;j<columnName.length;j++) {
                out.print("<td>"+table[i][j]+"</td>");
            }
            out.print("</tr>");
        }
    }
%>
</table>
<p id =tom>全部记录数:<jsp:getProperty name="recordBean" property="totalRecords"/>。
<br>每页最多显示<jsp:getProperty name="recordBean" property="pageSize"/>条记录。
<br>当前显示第<jsp:getProperty name="recordBean" property="currentPage"/>页
(共有<jsp:getProperty name="recordBean" property="totalPages"/>页)。</p>
<table id =tom>
<tr>
  <td><form  action="" method=post>
     <input type=hidden name="currentPage" 
                   value="<%=recordBean.getCurrentPage()-1 %>"/>
     <input type=submit id =tom value="上一页"/></form>
  </td>
  <td><form action="" method=post>
     <input type=hidden name="currentPage" 
                   value="<%=recordBean.getCurrentPage()+1 %>"/>
     <input type=submit id =tom name="g" value="下一页"></form>
  </td>
   <td> <form action="" id =tom method=post>
     输入页码:<input type=textid =tom  name="currentPage" size=2 >
     <input type=submit id =tom value="提交"></form>
   </td>
</tr>
<tr><td></td><td></td>
  <td><form action="" id =tom method=post>
  每页显示
  <input type=text id =tom name="pageSize" 
   value =<%= recordBean.getPageSize()%> size=1>条记录
  <input type=submit id =tom value="确定"></form></td>
</tr>
</table>
<a href = "example8_8_input.jsp">重新输入数据库和表名</a>
</center></body></HTML> 

3.servlet(控制器)

Query_Sevlet负责创建名字是query的servlet。query查询数据库表中的全部记录,将结果存放到id是recordBeant的session bean中,然后请求example8_8_show.jsp显示recordBean中的数据。

用命令行进入handle\data的父目录classes,编译Query_Servlet.java(本章开始的约定):

classes> javac -cp .;servlet-api.jar  handle/data/Query_Servlet.java

4.web.xml(部署文件)

向ch8\WEB\INF\下的部署文件web.xml添加如下的servlet和servlet-mapping标记(知识点见6.1.2),部署的servlet的名字是query,访问servlet的url-pattern是/ query。

结果:

8.9连接SQL Server与Access数据库

8.9.1 连接Microsoft SQL Server数据库

1. 登录www.micsosoft.com下载Microsoft JDBC Driver 6.0 for SQL Server,即下载sqljdbc_6.0.8112.200_chs.tar.gz。在解压目录的sqljdbc_6.0\chs\jre8子目录中可以找到JDBC-SQLServer连接器:sqljdbc42.jar。

将SQLServer 数据库的JDBC-SQLServer数据库连接器sqljdbc42.jar保存到Tomcat安装目录下的lib文件夹中(例如D:\apache-tomcat-9.0.26\lib),并重新启动Tomcat服务器。 应用程序加载JDBC-SQLServer数据库连接器的代码如下:

try {  Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

}

catch(Exception e){

}

2. 建立连接

try{    

 String url= "jdbc:sqlserver://192.168.100.1:1433;DatabaseName=warehouse";    

  String user="sa";    

  String password="dog123456";    

  con=DriverManager.getConnection(url,user,password);  

 }

catch(SQLException e){

}

8.9.2 连接Microsoft Access数据库

1.登录: http://www.hxtt.com/access.zip 下载JDBC-Access连接器。解压下载得access.zip,在解压目录下\lib子目录中的Access_JDBC30.jar就是JDBC-Access连接器,将Access_JDBC30.jar保存到Tomcat安装目录下的lib文件夹中,并重新启动Tomcat服务器。

加载Access数据库连接器程序的代码是:

Class.forName("com.hxtt.sql.access.AccessDriver");

2. 建立连接

将bookDatabase.accdb数据库保存在启动Tomcat服务器的当前目录下,即Tomcat安装目录的bin中。

String path = "./bookDatabase.accdb";

String loginName ="";

String password ="";

con =

DriverManager.getConnection("jdbc:Access://"+path,loginName,password);

8.10使用连接池

8.10.1 连接池简介

连接池的思想是,

■由一个管理者,比如Tomcat服务器,事先建立好若干个连接放在一起(存放在一个实现DataSource接口的对象中),称作一个连接池。

■当Web应用程序需要连接数据库时,只需到连接池中获得一个Connection对象即可。

■当Web应用程序不再需要Connection对象时,就让Connection对象调用close()方法,这样就可以把这个Connection对象再返回到连接池中,以便其他Web应用程序使用这个Connection对象。

■需要注意的是,Tomcat服务器提供的连接池中的Connection对象调用close()方法不会关闭和数据库的TCP连接,其作用仅仅是把Connection对象返回到连接池(这一点和Web应用程序自己创建的Connection对象不同,其原理不必深究)。

简单地说,连接池可以让Web应用程序方便地使用Connection对象(用完务必放回),再用再取,节省了创建Connection的时间,提高了Web应用程序访问数据库的效率。

8.10.2 建立连接池

为了让Tomcat服务器创建连接池,必须编写一个xml文件,Tomcat服务器通过读取该文件创建连接池。xml文件的名字必须是context.xml。

■连接池配置文件context.xml文件保存在Web服务目录的META-INF子目录中(不必重新启动Tomcat服务器)。

<?xml version="1.0" encoding="utf-8" ?>

<Context>  

<Resource    

name = "gxy"  

  type ="javax.sql.DataSource"    

driverClassName = "com.mysql.cj.jdbc.Driver"    

url = "jdbc:mysql://127.0.0.1:3306/bookDatabase?useSSL=false            &amp;serverTimezone=CST&amp;characterEncoding=utf-8"    

username ="root"    

password =""    

maxActive ="15"    

maxIdle ="15"    

minIdle ="1"    

maxWait ="1000"  

/>

</Context>

name:设置连接池的名字(命名一个喜欢的名字即可),例如gxy,该名字是连接池的id,context.xml文件中,如果有多个Resource标记(一个Resource标记对应一个连接池),必须保证这些Resource标记中的name互不相同,即context.xml文件可以给出多个不同连接池的配置信息。

type: 设置连接池的类型,这里必须是javax.sql.DataSource driverClassName:设置数据库连接器,即数据库驱动的类。

url:设置连接数据库的URL,注意url要小写。需要注意的是对于url中的 &字符要写成“&amp;”,这是XML文件对特殊字符的一个特殊规定。

username:给出可以访问数据库的用户名,例如root。 password :给出访问数据库的密码,比如,root用户的默认密码是无密码。

maxActive:设置连接池的大小,即连接池中处于活动状态Connection对象的数目。

maxIdle :设置连接池中可处于空闲状态的Connection对象的最大数目。

maxWait :设置连接池中没有空闲状态Connection对象可用时,用户请求获得连接池中Connection对象需要等待的最长时间(单位是毫秒)。

2.使用连接池

步骤如下:

(1)Context接口 首先创建一个实现Context(上下文)接口的对象:

Context  context = new InitialContext();

然后让context去寻找Tomcat服务器曾绑定在运行环境中的另一个Context对象:

Context  contextNeeded = (Context)context.lookup("java:comp/env");

其中的java:comp/env是Tomcat服务器绑定这个Context对象时使用的资源标志符(不可以写错)。

(2)得到连接池  连接池绑定在Context对象contextNeeded中。绑定用的资源标志符是连接池配置文件context.xml中name给的值,比如gxy。  

 DataSource  ds = (DataSource)contextNeeded.lookup("gxy");

(3)从连接池中获得连接

  Connection con  = ds.getConnnection();

(4)将连接返回连接池

con.close();

8.11标准化考试训练

8.11.1 功能概述

1. Web应用程序-标准化考试训练有2个JSP页面,example8_11_start.jsp和example8_11_exm.jsp。用户首先访问example8_11_start.jsp页面,在该页面输入训练题目的数量,单击提交键请求名字是givePaper的servlet。givePaper servlet将一套试题存放在名字是paperBean的session bean中,然后将用户定向到example8_11_exam.jsp页面。

2 . example8_11_exam.jsp页面显示paperBean中的数据,用户根据显示的内容开始答题。用户给出一道题目的回答,即给出用户的答案,单击“确认”提交键,请求名字是handleMess的servlet,handleMess servlet负责将用户的给出答案存储到paperBean中,并将用户再定向到example8_11_exam.jsp页面。用户单击“下一题”或“上一题”提交键,请求名字是handleMess的servlet,handleMess servlet负责将下一题或上一题的题目内容存储到paperBean中,并将用户再定向到example8_11_exam.jsp页面。用户单击该页面上 “交卷”的提交键,请求名字是giveScore的servlet,giveScore servlet负责计算用户的得分并显示得分。

8.11.2 数据库设计

sql文件createDatabase.sql,保存在D:\myFile目录中

1.数据库与表

使用mysql命令行启动客户端:

mysql  -u root -p

按要求输入密码后,执行操作

source D:/myFile/createDatabase.sql;

导入该sql文件中的SQL语句,完成数据库、表的创建。如果某个题目不需要图像,那么插入记录时让pic字段的值为''(只输入一对单引号),即长度为0的字符序列,answer字段的值用大写英文字母A,B,C或D(有关创建数据库和表的细节见8.1.3)。

2.数据库连接池

标准化考试训练系统准备使用连接池连接数据库。打开ch8\META-INF下的连接池配置文件context.xml,增加名字是examinationConn的连接池。

<?xml version="1.0" encoding="utf-8" ?>
<Context>
  <!-- 以下是新增加的内容(连接池)-->
  <Resource 
    name = "examinationConn"
    type ="javax.sql.DataSource"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/Examination?useSSL=false
        &amp;serverTimezone=CST&amp;characterEncoding=utf-8"
    username ="root"
    password =""
    maxActive ="20"
    maxIdle ="20"
    minIdle ="1"
    maxWait ="5000" 
   /> 
</Context>

1.bean(模型)

bean的id是paperBean,是session bean,用于存储一套试题,paperBean由servlet负责用TestPaperBean类创建。TestPaperBean类需要组合的Problem类的实例。id是problem的bean也是session bean,用于存储一道题目,具体是哪一道题目由paperBean来确定。

用命令行进入save\data的父目录classes,编译Problem.java和TestPaperBean.java(见本章开始的约定):

javac  save\data\ Problem.java

javac  save\data\ TestPaperBean.java

2.JSP页面(视图)

视图部分由两个JSP页面构成,其中example8_11_start.jsp页面负责提供输入试题数量的视图,在该页面输入训练的试题数量,然后请求名字是givePaper的servlet。servlet负责查询数据库,并将结果存储到id为paperBean的session bean中,然后请求视图中的example8_11_exam.jsp页面显示paperBean中的数据。

example8_11_start.jsp

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %>
<style>
   #tom{
      font-family:宋体;font-size:26;color:blue 
   }
</style>
<h1>标准化考试训练</h1>
<HTML><body bgcolor=#ffccff>
<form action='givePaper' id='tom' method='post' ><br>
输入训练题目数量:
<input type='text' id='tom' name='testAmount' value=10 size=2 />
<input type='submit' id='tom' name='submit' value='提交'/>
</form> 
</body></HTML>

example8_11_exam.jsp

<%@ page contentType="text/html" %>
<%@ page pageEncoding = "utf-8" %>
<style>
   #tom{
      font-family:宋体;font-size:20;color:blue 
   }
</style>
<jsp:useBean id="problem" class="save.data.Problem" scope="session"/>
<jsp:useBean id="paperBean" 
             class="save.data.TestPaperBean" scope="session"/>
<HTML><body bgcolor=#DEEFF9>
<% request.setCharacterEncoding("utf-8");
   problem = paperBean.getCurrentProblem();
%>
<p id = tom><%=problem.index%>.
<%= problem.content %>
</p>
<% if(problem.imageName.length()>0) {
%>   <image src =image/<%=problem.imageName%> width=300 height=260>
     </image>
<% }
%>
<form action="handleMess" id=tom method=post >
    <input type="radio" id=tom name="R" value=A /><%=problem.choiceA%> 
    <input type="radio" id=tom name="R" value=B /><%=problem.choiceB%>
<br><input type="radio" id=tom name="R" value=C /><%=problem.choiceC%>
    <input type="radio" id=tom name="R" value=D /><%=problem.choiceD%>
<br><input type="submit" id=tom value="确认(可反复确认)" name="submit" />
</form>
<form action="handleMess" method=post name=form>
  <input type="submit" id=tom value="上一题" name="submit" />
  <input type="submit" id=tom value="下一题" name="submit" />
</form> 
<form action="giveScore" method=post >
    <input type="submit" id=tom value="交卷" name="submit" />
</form> 
</body></HTML>  

3.servlet(控制器)

GiveTestPaper_Servlet.java

GiveTestPaper_Servlet负责创建名字是givePaper的servlet。givePape查询数据库testQuesion表中的全部记录,将结果存放到id是paperBean的session bean中,然后请求example8_11_exam.jsp显示paperBean中的数据。

HandleMess_Servlet.java

HandleMess_Servlet负责创建名字是handleMess的servlet。handleMess servlet负责将用户的给出答案存储到paperBean中,并将用户再定向到example8_11_exam.jsp页面。用户单击“下一题”或“上一题”提交键,handleMess servlet负责将下一题或上一题的题目内容存储到paperBean中,并将用户再定向到example8_11_exam.jsp页面。

GiveScore_Servlet.java

GiveScore_Servlet负责创建名字是giveScore的servlet。用户单击该页面上 “交卷”的提交键,giveScore servlet负责计算用户的得分并显示得分。

命令行进入handle\data的父目录classes,编译GiveTestPaper_Servlet.java,HandleMess_Servlet.java和GiveScore_Servlet.java(本章开始的约定):

javac -cp .;servlet-api.jar  handle/data/GiveTestPaper_Servlet.java

javac -cp .;servlet-api.jar  handle/data/HandleMess_Servlet.java

javac -cp .;servlet-api.jar  handle/data/GiveScore_Servlet.java

4.web.xml(部署文件)

向ch8\WEB\INF\下的部署文件web.xml添加servlet和servlet-mapping标记(知识点见6.1.2),部署的servlet的名字分别是givePaper,handleMess和giveScore,访问servlet的url-pattern分别是/givePaper,/handleMess和/giveScore。

5.图像的存放位置

Web应用中的需要的图像文件保存在Web服务目录的image子目录中,图像文件的名字是数据库Examination中testQuesion表的pic字段的值,比如p1.jpg,p2.jpg…等

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值