JDBC 技术
- 本章节学习的目的是了解数据库在 JSP 中的操作及其应用,要求理解 JDBC 技术并能够熟练运用 JDBC 技术进行 JSP 案例开发。
三、查询数据库
- 数据查询是数据库的一项基本操作,通常使用结构化查询语言(Structure Query Language)和 ResultSet 对记录进行查询。查询的方法有很多,可以分为顺序查询、带参数查询、模糊查询和查询分析等。SQL 是标准的结构化查询语言,可以在任何数据库管理系统中使用,因此被普片使用,其语法如下:
select list from table
[where search_condition]
[group by group_by_expression[asc/desc]]
[order by order_expression [asc/desc]]
- 各参数的含义如下:
参数 | 含义 |
---|---|
list | 目标列表达式。用来指明要查询的列名,或者有列名参与的表达式。用 * 代表所有列 |
table | 指明要查询的表的名称。可以是一张表,也可以是多张表。如果不同表中有相同列,需要用“表名.列名”的方式指明该列来自哪张表 |
search_condition | 查询条件表达式。用来指定查询的条件 |
group_by_eapression | 分组查询表达式。按表达式条件将记录分为不同的记录组参与运算,通常与目标列表达式中的函数配合使用,实现分组统计功能 |
order_expression | 排列查询表达式。按指定表达式的值来对满足条件的记录进行排序,默认是升序 |
- SQL 中的查询语句除了可以实现单表查询以外,还可以实现多表查询和嵌套查询,使用起来比较灵活。
- JDBC 提供3种接口实现 SQL 语句的发送执行,分别是 Statement、PreparedStatement 和 CallableStatement。Statement 接口的对象用于执行简单的不带参数的 SQL 语句;PreparedStatement 接口的对象用于执行带有 IN 类型参数的预编译过的 SQL 语句;CallableStatement 接口的对象用于执行一个数据库的存储过程。PreparedStatement 继承了 Statement,而 CallableStatement 又从 PreparedStatement 继承而来。通过上述对象发送 SQL 语句,由 JDBC 提供的 ResultSet 接口对结果集中的数据进行操作。
1.Statement
- 使用 Statement 发送要执行的 SQL 语句前,首先要创建 Statement 对象实例,然后根据参数 type、concurrency 的取值情况返回 Statement 类型的结果集。语法格式为:
Statement stmt = con.creareStatement(type,concurrency);
- 其中,type 属性用来设置结果集的类型。type 属性有三种取值:
ResultSet.TYPE_FORWORD_ONLY | 代表结果集的记录指针只能向下滚动 |
---|---|
ResultSet.TYPE_SCRPLL_INSENSITIVE | 代表结果集的记录指针可以上下滚动,数据库变化时,当前结果集不变 |
ResultSet.TYPE_SCROLL_SENSITIVE | 代表结果集的记录指针可以上下滚动,数据库变化时,结果集随之变化 |
- Concurrency 属性用来设置结果集更新数据库的方式。它也有两种取值:
ResultSet.CONCUR_READ_ONLY | 代表不能用结果集更新数据库中的表 |
---|---|
ResultSet.CONCUR_UPDATETABLE | 代表可以更新数据库 |
- Statement 还提供了一些操作结果集的方法,Statement 的常用方法如表所示:
方法 | 说明 |
---|---|
executeQuery() | 用来执行查询 |
executeUpdate() | 用来执行更新 |
execute() | 用来执行动态的未知操作 |
setMaxRow() | 设置结果集容纳的最多行数 |
getMaxRow() | 获得结果集的最多行数 |
setQueryTimeOut() | 设置一个语句的执行等待时间 |
getQueryTimeOut() | 获取一个语句的执行等待时间 |
close() | 关闭 Statement 对象,释放其资源 |
2.PreparedStatement
- PreparedStatement 可以将 SQL 语句传给数据库做预编译处理。即在执行的 SQL 语句中包含一个或多个 IN 参数,可以通过设置 IN 参数值多次执行 SQL 语句,而不必重新编译 SQL 语句,这样可以大大提高执行 SQL 语句的速度。所谓 IN 参数就是指那些在 SQL 语句创建时尚未指定值的参数,在 SQL 语句中 IN 参数用 “?” 代替。举个例子:
PreparedStatement pstmt = connection.preparedStatement("select * from student where 年龄 >= ? and 性别 = ?")
- 这个 PreparedStatement 对象用来查询表中符合指定条件的信息,在执行查询之前必须对每个 IN 参数进行设置,设置 IN 参数的语法格式为:
pstmt.setXXX(position,value);
其中,XXX为要设置数据的类型,position 为 IN 参数在 SQL 语句中的位置,value 指参数被设置的值。例如:pstmt.setInt(1,20);
- 举个代码例子:
String sql = "select * from info where studentAge >= ? and studentAge <= ?";
PreparedStatement stmt = conn.preparedStatement(sql);
stmt.setInt(1,18);
stmt.setInt(2,20);
ResultSet rs = stmt.executeQuery();
while(rs.next()){
.
.
.
}
3.ResultSet
- 可以通过 ResultSet 的方法在结果集中进行滚动查询。常用的查询方法如表所示:
方法 | 说明 |
---|---|
next() | 将记录指针向下滚动,当移动到结果集最后一行之后时返回 false |
previous() | 将记录指针向上移动,当移动到结果集第一行之前时返回 false |
beforeFirst() | 将记录指针移动到结果集的第一行之前 |
afterLast() | 将记录指针移动到结果集的最后一行之后 |
first() | 将记录指针移动到结果集的第一行 |
last() | 将记录指针移动到结果集的最后一行 |
isAfterLast() | 判断记录指针是否到达结果集的最后一行之后 |
isFirst() | 判断记录指针是否到达结果集的第一行 |
isLast() | 判断记录指针是否到达结果集的最后一行 |
getRow() | 返回当前记录指针所指向的行号,行号从1开始,如果没有记录返回结果为0 |
absolute(int row) | 将记录指针移动到指定的第 row 行 |
close() | 关闭 ResultSet 对象,并释放它所占的资源 |
- 举个代码例子:
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
String sql = "select * from info";
ResultSet rs = stmt.executeQuery(sql);
rs.last();
rs.afterLast();
while(rs.previous()){
.
.
.
}
四、更新数据库
- 更新数据库是数据库的基本操作,因为数据库中的数据是不断变化的。通过执行增加、修改、删除操作,可以使数据库中的数据保持动态更新。
1.添加操作
- 在 SQL 中,使用 insert 语句就可以将新行添加到表或视图中,语法格式如下:
insert into table_name column_list values({default|null|expression},[,...n]);
- 其中,table_name 指定将要插入数据的表或 table 变量的名称;column_list 是要在其中插入数据的一列或多列的列表,必须用圆括号将 column_list 括起来,并且用逗号分隔;values({default|null|expression},[,…n]) 引入要插入的数据值的列表。对 column_list(如果已指定)中或者表中的每个列,都必须有一个数据值,且必须用圆括号将值列表括起来。
2.修改操作
- SQL 中的更新语句是 update 语句,其语法格式如下:
update table_name set column_name = expression[,column_name1 = expression]
[where search_condition];
- 其中,table_name 用来指定需要更新的表的名称;set column_name = expression[,column_name1 = expression] 指定要更新的列或变量名称的列表,column_name 指定要更改数据列的名称;where search_condition 指定条件来限定所要更新的行。
3.删除操作
- 在 SQL 中,使用 delete 语句删除数据表中的行。delete 语句的语法格式如下:
delete from table_name [where search_condition];
- 其中,table_name 用来指定表;where 用来指定限制删除操作的条件。如果没有提供 where 子句,则 delete 删除表中的所有数据。
4.应用实例
- 更新数据库实例。本例有一个添加学生信息页面(input.jsp),在该页面输入信息。单击提交按钮后请求提交到 inputCheck.jsp 页面,该页面实现了对数据的添加、更改和删除操作。所用的数据库名称为 student,表名为 info,数据如图所示:
- 学生信息页面(input.jsp)代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP 中更新数据库</title>
</head>
<body bgcolor = "CCCFFF">
<br><br>
<center>
<form action = "inputCheck.jsp" method = "post">
<h2>输入要添加学生的信息</h2>
<hr>
<table>
<tr>
<td>学号</td>
<td><input type = "text" name = "studentNumber"></td>
</tr>
<tr>
<td>姓名</td>
<td><input type = "text" name = "studentName"></td>
</tr>
<tr>
<td>性别</td>
<td><input type = "text" name = "studentSex"></td>
</tr>
<tr>
<td>年龄</td>
<td><input type = "text" name = "studentAge"></td>
</tr>
<tr>
<td>体重 </td>
<td><input type = "text" name = "studentWeight"></td>
</tr>
<tr align = "center">
<td colspan = "2">
<input type = "submit" value = "提交" name = "sure">
<input type = "reset" value = "取消" name = "clear">
</td>
</tr>
</table>
<hr>
</form>
</center>>
</body>
</html>
- 页面效果如下:
- inputCheck.jsp 页面代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import = "java.sql.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>数据更新后的页面</title>
</head>
<body bgcolor = "CCCFFF">
<center>
<h3>已添加学生信息</h3>
<hr>
<%
// 代码转换,把中文转换成标准的字符方式
String studentNumber = request.getParameter("studentNumber");
byte b[] = studentNumber.getBytes("ISO-8859-1");
studentNumber = new String (b,"UTF-8");
String studentName = request.getParameter("studentName");
byte b1[] = studentName.getBytes("ISO-8859-1");
studentName = new String (b1,"UTF-8");
String studentSex = request.getParameter("studentSex");
byte b2[] = studentSex.getBytes("ISO-8859-1");
studentSex = new String (b2,"UTF-8");
String studentAge = request.getParameter("studentAge");
byte b3[] = studentAge.getBytes("ISO-8859-1");
studentAge = new String (b3,"UTF-8");
String studentWeight = request.getParameter("studentWeight");
byte b4[] = studentWeight.getBytes("ISO-8859-1");
studentWeight = new String (b4,"UTF-8");
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://localhost:1433;databasename = student";
String user = "sa";
String password = "2017212027";
Connection conn = DriverManager.getConnection(url,user,password);
Statement stmt = conn.createStatement();
String sql = "insert into info values('"+studentNumber+"','"+studentName+"','"+studentSex+"','"+studentAge+"','"+studentWeight+"')";
stmt.execute(sql);
stmt.close();
conn.close();
%>
<h3>已更改学生信息</h3>
<hr>
<%
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url1 = "jdbc:sqlserver://localhost:1433;databasename = student";
String user1 = "sa";
String password1 = "2017212027";
Connection conn1 = DriverManager.getConnection(url1,user1,password1);
Statement stmt1 = conn1.createStatement();
String sql1 = "update info set studentAge = 18";
stmt1.executeUpdate(sql1);
stmt1.close();
conn1.close();
%>
<h3>已删除学生信息</h3>
<hr>
<%
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url2 = "jdbc:sqlserver://localhost:1433;databasename = student";
String user2 = "sa";
String password2 = "2017212027";
Connection conn2 = DriverManager.getConnection(url2,user2,password2);
Statement stmt2 = conn2.createStatement();
String sql2 = "delete from info where studentSex = '男'";
stmt2.executeUpdate(sql2);
stmt2.close();
conn2.close();
%>
<h3>经过以上操作后,数据库中有以下记录</h3>
<hr>
<table border = "2" bgcolor = "CCCEEE" align = "center">
<tr>
<td>学号</td>
<td>姓名</td>
<td>性别</td>
<td>年龄</td>
<td>体重</td>
</tr>
<%
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url3 = "jdbc:sqlserver://localhost:1433;databasename = student";
String user3 = "sa";
String password3 = "2017212027";
Connection conn3 = DriverManager.getConnection(url3,user3,password3);
Statement stmt3 = conn3.createStatement();
String sql3 = "select * from info";
ResultSet rs = stmt3.executeQuery(sql3);
while(rs.next()){
%>
<tr>
<td><%=rs.getString("studentNumber") %></td>
<td><%=rs.getString("studentName") %></td>
<td><%=rs.getString("studentSex") %></td>
<td><%=rs.getString("studentAge") %></td>
<td><%=rs.getString("studentWeight") %></td>
</tr>
<%
}
rs.close();
stmt3.close();
conn3.close();
%>
</table>
<hr>
</center>
</body>
</html>
- 页面效果如下:
五、JSP 中数据库应用的常见问题
1.JSP 的分页技术
- 在实际应用中,如果从数据库中查询得到的记录特别多,甚至超过了显示器屏幕范围,课件结果分页显示。
- 分页显示实例,pageBreak.jsp 代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import = "java.sql.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>分页实例</title>
</head>
<body bgcolor = "CCBBDD">
<center>
<h3>分页显示内容</h3>
<hr>
<table border = "1" width = "50%" bgcolor = "CCCFFF" align = "center">
<tr>
<th>学号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>体重</th>
</tr>
<%
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://localhost:1433;databasename = student";
String user = "sa";
String password = "2017212027";
Connection conn = DriverManager.getConnection(url,user,password);
int intPageSize; //一页显示的记录数
int intRowCount; //记录总数
int intPageCount; //总页数
int intPage; //待显示页码
String strPage;
int i;
intPageSize = 2;
strPage = request.getParameter("page"); //取得待显示页码
if(strPage == null){
// 表名 page 的参数值为空,此时显示第一页数据
intPage = 1;
}else{
//将字符串转换为整型
intPage = java.lang.Integer.parseInt(strPage);
if(intPage < 1)
intPage = 1;
}
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
String sql = "select * from info";
ResultSet rs = stmt.executeQuery(sql);
rs.last();
intRowCount = rs.getRow();
intPageCount = (intRowCount + intPageSize - 1) / intPageSize;
if(intPage > intPageCount)
intPage = intPageCount;
if(intPageCount > 0){
rs.absolute((intPage - 1) * intPageSize + 1);
i = 0;
while(i < intPageSize && !rs.isAfterLast()){
%>
<tr>
<td><%=rs.getString("studentNumber") %></td>
<td><%=rs.getString("studentName") %></td>
<td><%=rs.getString("studentSex") %></td>
<td><%=rs.getString("studentAge") %></td>
<td><%=rs.getString("studentWeight") %></td>
</tr>
<%
rs.next();
i++;
}
}
%>
</table>
<hr>
<div align = "center">
第<%=intPage %>页 共<%=intPageCount %>页
<%
if(intPage < intPageCount){
%>
<a href = "pageBreak.jsp?page=<%=intPage + 1 %>">下一页</a>
<%
}
if(intPage >1){
%>
<a href = "pageBreak.jsp?page=<%=intPage - 1 %>">上一页</a>
<%
}
rs.close();
stmt.close();
conn.close();
%>
</div>
</center>
</body>
</html>
- 页面效果如图: