第5章 JSP中使用数据库
在JSP中可以使用Java的JDBC技术,实现对数据库中表记录的查询、修改和删除等操作。JDBC技术在JSP开发中占有很重要的地位。
JDBC(Java DataBase Connectivity)是Java数据库连接API。简单地说,JDBC能完成三件事:
(1) 与一个数据库建立连接,
(2) 向数据库发送SQL语句,
(3) 处理数据库返回的结果。
JDBC在设计上和ODBC很相似。JDBC和数据库建立连接的一种常见方式是建立起一个JDBC─ODBC桥接器。由于ODBC驱动程序被广泛的使用,建立这种桥接器后,使得JDBC有能力访问几乎所有类型的数据库。JDBC也可以直接加载数据库驱动程序访问数据库,我们将在2.8节讨论。
如果使用JDBC─ODBC桥接器访问数据库,事先必须设置数据源。
5.1 数据源
假设要访问SQL Server服务器上的pubs数据库,该库有一个表students,如图5.1、5.2所示。
为连接一个SQL-Server数据库,我们需设置一个数据源。在控制面板选择ODBC数据源,如图5.3所示。
双击ODBC数据源图标。出现如图5.4所示界面,图5.4中显示了用户已有的数据源的名称。
选择“用户DSN”,点击add按钮,增加新的数据源。如图5.5所示:
为新增的数据源选择驱动程序,因为要访问SQL Server数据库,选择SQL Server,点击完成按钮(为数据源选择了驱动程序),出现设置数据源具体项目的对话框,如图5.6所示。在名称栏里为数据源起一个你自己喜欢的名字,这里我们起的名字是sun(当然,如果你喜欢的话,可以把名字叫做moon.)。这个数据源就是指某个数据库(将来随着计算机的进步,我们也可能有能力把数据源设成是一个卫星上来的信号)。在“你想连接哪个SQL Server?”栏中选择或输入一个数据库服务器,这里我们选择了网络上的另一台机器:Ping。
单击“下一步”出现图5.7画面,选择连接SQL Server 的ID。
在图5.7的对话框中,选择“使用用户输入登录标识号和密码的SQL Server验证”选项,在这里我们选择用户名为sa (不需要密码),单击“下一步”出现如图5.8所示的选择数据库的对话框。
选中“改变默认的数据库为”复选框,在下拉菜单里,我们选择用户sa有权限操作的数据库pubs。单击“下一步”出现完成数据源设置的对话框如图5.9。
在图5.9中,单击“完成”出现你所配置的数据源的信息窗口,如图5.10所示。
点击“测试数据源”按钮,如果正常就会出现数据源设置成功的窗口,如图5.11所示。
5.2 JDBC-ODBC桥接器
现在你可以这样的直观理解:我们有了一个数据源,这个数据源就是一个数据库。为了要连接到这个数据库,需要建立一个JDBC─ODBC桥接器,即加载桥接器驱动程序。
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
这里,Class是包java.lang中的一个类,该类通过调用它的静态方法forName就可以建立JDBC-ODBC桥接器。建立桥接器时可能发生异常,所以建立桥接器的标准是:
try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e)
{}
5.3 查询记录
要查询数据库中的记录,必须和数据库建立连接,由于使用的是JDBC-ODBC方式访问数据库,那么就要与数据源建立连接。
(1)连接到数据库
首先使用包java.sql中的Connection类声明一个对象,然后再使用类DriverManager调用它的静态方法getConnection创建这个连接对象:
Connection con = DriverManager.getConnection("jdbc:odbc:数据源名字","login name", "password ");
假如您没有为数据源设置login name 和password,那么连接形式是:
Connection con = DriverManager. getConnection("jdbc:odbc:数据源名字", "", "");
与数据库pubs(它就是数据源sun)建立连接,格式如下:
try{ Connection con = DriverManager. getConnection("jdbc:odbc:sun", "sa", "");
}
catch(SQLException e)
{}
这样就建立了到数据库pubs的连接。
(2)向数据库发送SQL语句。
首先使用Statement声明一个SQL语句对象,然后通过刚才创建的连接数据库的对象con调用方法createStatment()创建这个SQL语句对象。
try {Statement sql=con.createStatement();}
catch(SQLException e ){}
(3)处理查询结果
有了SQL语句对象后,这个对象就可以调用相应的方法实现对数据库中表的查询和修改。并将查询结果存放在一个ResultSet类声明的对象中,也就是说SQL语句对数据库的查询操作将返回一个ResultSet对象:
ResultSet rs=sql.executeQuery("SELECT * FROM 成绩表");
ResultSet对象是以统一形式的列组织的数据行组成。ResultSet对象一次只能看到一个数据行,使用next()方法走到下一数据行,获得一行数据后,ResultSet对象可以使用getxxxx方法获得字段值,将位置索引(第一列使用1,第二列使用2等等)或字段名传递给getxxxx方法的参数即可。
ResultSet类的若干方法
l boolean next()
l byte getByte(int columnIndex)
l Date getDate(int columnIndex)
l double getDouble(int columnIndex)
l float getFloat(int columnIndex)
l int getInt(int columnIndex)
l long getLong(int columnIndex)
l String getString(int columnIndex)
l byte getByte(String columnName)
l Date getDate(String columnName)
l double getDouble(String columnName)
l float getFloat(String columnName)
l int getInt(String columnName)
l long getLong(String columnName)
l String getString(String columnName)
5.3.1 顺序查询
使用结果集Result的next()方法,可以顺序的查询。一个结果集将游标最初定位在第一行的前面,第一次调用next()方法使游标移动到第一行。next()方法返回一个boolean型数据,当游标移动到最后一行之后返回false。
在下面的例子1中,我们查询数据库pubs(数据源sun)中students表里的包含全部字段的记录。
例子1(效果如图5.12所示)
Example5_1.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
rs=sql.executeQuery("SELECT * FROM students");%>
<Table Border>
<TR>
<TH width=100>学号
<TH width=100姓名
<TH width=50>数学成绩
<TH width=50>英语成绩
<TH width=50>物理成绩
</TR>
<% while(rs.next())
{ out.print("<TR>");
out.print("<TD >"+rs.getString(1)+"</TD>");
out.print("<TD >"+rs.getString(2)+"</TD>");
out.print("<TD >"+rs.getInt("数学成绩")+"</TD>");
out.print("<TD >"+rs.getInt("英语成绩")+"</TD>");
out.print("<TD >"+rs.getInt("物理成绩")+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {}
%>
</BODY>
</HTML>
在下面的例子2中查询“英语成绩”字段值大于80的记录,但只显示“姓名”字段(第2个字段)和“英语成绩”字段。
例子2(效果如图5.13所示)
Example5_2.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
rs=sql.executeQuery("SELECT * FROM students WHERE 英语成绩 >= 80 ");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"英语成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
out.print("<TD >"+rs.getString(2)+"</TD>");
out.print("<TD >"+rs.getInt("英语成绩")+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {}
%>
</BODY>
</HTML>
5.3.2 游动查询
前面我们学习了使用Result的next()方法顺序地查询数据,但有时候我们需要在结果集中前后移动、或显示结果集指定的一条记录等等。这时,我们必须要返回一个可滚动的结果集。为了得到一个可滚动的结果集,和上一节不同的是,我们必须使用下述方法先获得一个Statement对象:
Statement stmt=con.createStatement(ResultSet.TYPE_FORWORD_ONLY ,int concurrency);
然后,根据参数的type、concurrency的取值情况,stmt返回相应类型的结果集:
ResultSet re=stmt.executeQuery(SQL语句);
type的取值决定滚动方式,取值可以是:
l ResultSet.TYPE_FORWORD_ONLY :结果集的游标只能向下滚动。
l ResultSet.TYPE_SCROLL_INSENSITIVE :结果集的游标可以上下移动,当数据库变化时,当前结果集不变。
l ResultSet.TYPE_SCROLL_SENSITIVE :返回可滚动的结果集,当数据库变化时,当前结果集同步改变。
Concurrency 取值决定是否可以用结果集更新数据库,Concurrency取值:
l ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。
l ResultSet.CONCUR_UPDATETABLE:能用结果集更新数据库中的表。
滚动查询经常用到ResultSet的下述方法:
l public boolean previous():将游标向上移动,该方法返回boolean型数据,当移到结果集第一行之前时返回false.
l public void beforeFirst:将游标移动到结果集的初始位置,即在第一行之前。
l public void afterLast():将游标移到结果集最后一行之后。
l public void first():将游标移到结果集的第一行。
l public void last():将游标移到结果集的最后一行。
l public boolean isAfterLast():判断游标是否在最后一行之后。
l public boolean isBeforeFirst():判断游标是否在第一行之前
l public boolean ifFirst():判断游标是否指向结果集的第一行。
l public boolean isLast():判断游标是否指向结果集的最后一行。
l public int getRow():得到当前游标所指行的行号,行号从1开始,如果结果集没有行,返回0
l public boolean absolute(int row):将游标移到参数row指定的行号。
注意,如果row取负值,就是倒数的行数,absolute(-1)表示移到最后一行,absolute(-2)表示移到倒数第2行。当移动到第一行前面或最后一行的后面时,该方法返回false。
在下面的例子中,首先将游标移动到最后一行,然后再获取行号,这样就获得表中的记录数目。然后我们倒序输出结果集中的记录,即首先输出最后一行。最后单独输出第5条记录。
例子3(效果如图5.14所示)
Example5_3.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% String name,number;
int math,physics,english;
Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try{ con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
//返回可滚动的结果集:
rs=sql.executeQuery("SELECT * FROM students");
//将游标移动到最后一行:
rs.last();
//获取最后一行的行号:
int lownumber=rs.getRow();
out.print("该表共有"+lownumber+"条记录");
out.print("<BR>现在逆序输出记录:");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
//为了逆序输出记录,需将游标移动到最后一行之后:
rs.afterLast();
while(rs.previous())
{ out.print("<TR>");
number=rs.getString(1);
out.print("<TD >"+number+"</TD>");
name=rs.getString(2);
out.print("<TD >"+name+"</TD>");
math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
out.print("单独输出第5条记录<BR>");
rs.absolute(5);
number=rs.getString(1);
out.print(number+",");
name=rs.getString(2);
out.print(name+",");
math=rs.getInt("数学成绩");
out.print(math+",");
english=rs.getInt("英语成绩");
out.print(english+",");
physics=rs.getInt("物理成绩");
out.print(physics+"。");
con.close();
}
catch(SQLException e1) {}
%>
</BODY>
</HTML>
5.3.3 随机查询
在下面的例子中,我们随机从结果集中取出4条记录,并计算4条记录的数学成绩的平均值。用Math类的静态方法random()可以产生一个大于0小于1的随机数,再用下述公式:
int i=(int)(Math.random()*number+1);
产生一个1到number之间的随机数,根据这个随机数将游标移动到相应的行,并输出该行,算法的进一步细节可见下述例子4。
例子4(效果如图5.15所示)
Example5_4.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% String xuehao,name;
int math;
Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
//返回可滚动的结果集:
rs=sql.executeQuery("SELECT * FROM students");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("</TR>");
//将游标移动到最后一行:
rs.last();
//获取最后一行的行号:
int lownumber=rs.getRow();
//获取记录数:
int number=lownumber;
double sum=0;
int 抽取数目=4;
int old_i[]={0,0,0,0};
int k=抽取数目;
int j=0;
while(抽取数目>0)
{int i=(int)(Math.random()*number+1);//随机获取一个1到number之间的数。
boolean boo=false;
for(int m=0;m<old_i.length;m++) //查找该行是否已被取出。
{if(i==old_i[m])
boo=true;
}
if(boo) continue; //假如该行已被取出,结束本次循环,继续产生随机数。
rs.absolute(i); //游标移到这一行。
out.print("<TR>");
xuehao=rs.getString(1); //获取该行学号字段的值。
out.print("<TD >"+xuehao+"</TD>");
name=rs.getString(2); //获取该行姓名字段的值。
out.print("<TD >"+name+"</TD>");
math=rs.getInt("数学成绩"); //获取改行数学成绩字段的值。
out.print("<TD >"+math+"</TD>");
out.print("</TR>") ;
sum=sum+math;
抽取数目--;
old_i[j]=i; //记录已取出的行号。
j++;
}
out.print("</Table>");
out.print("平均成绩是:"+sum/k);
con.close();
}
catch(SQLException e1) {}
%>
</BODY>
</HTML>
5.3.4 参数查询
在下面的例子中,客户通过Example5_5.jsp页面输入查询条件,如按姓名查询成绩或按分数段查询学生成绩等等。输入姓名提交给byname.jsp页面,输入分数段提交给byscore.jsp页面。
例子5(效果如图5.16、5.17、5.18所示)
Example5_5.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<HTML>
<BODY>
<Font size=1>
<FORM action="byname.jsp" Method="post">
<P>成绩查询
<P>输入姓名:
<Input type=text name="name">
<Input type=submit name="g" value="提交">
</Form>
<FORM action="byscore.jsp" Method="post" >
<P>根据分数查询名单:<BR> 英语分数在
<Input type=text name="englishmin" value=0>
和
<Input type=text name="englishmax" value=100>
之间
<BR> 数学分数在
<Input type=text name="mathmin" value=0>
和
<Input type=text name="mathmax" value=100>
之间
<BR> <Input type=submit value="提交">
</Form>
</BODY>
</HTML>
bynename.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% //获取提交的姓名:
String name=request.getParameter("name");
if(name==null)
{name="";
}
byte b[]=name.getBytes("ISO-8859-1");
name=new String(b);
Connection con=null;
Statement sql=null;
ResultSet rs=null;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
String condition="SELECT * FROM students WHERE 姓名 = "+"'"+name+"'";
rs=sql.executeQuery(condition);
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
out.print("<TD >"+rs.getString(1)+"</TD>");
out.print("<TD >"+rs.getString(2)+"</TD>");
out.print("<TD >"+rs.getInt("数学成绩")+"</TD>");
out.print("<TD >"+rs.getInt("英语成绩")+"</TD>");
out.print("<TD >"+rs.getInt("物理成绩")+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e)
{ }
%>
</BODY>
</HTML>
byscore.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% //获取提交的分数的最大值和最小值:
String englishmax=request.getParameter("englishmax");
if(englishmax==null)
{englishmax="100";
}
String englishmin=request.getParameter("englishmin");
if(englishmin==null)
{englishmin="0";
}
String mathmax=request.getParameter("mathmax");
if(mathmax==null)
{mathmax="100";
}
String mathmin=request.getParameter("mathmin");
if(mathmin==null)
{mathmin="0";
}
Connection con=null;
Statement sql=null;
ResultSet rs=null;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try
{ con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
String eCondition="英语成绩 <= "+englishmax+" AND "+"英语成绩 >= "+englishmin;
String mCondition="数学成绩 <= "+mathmax+" AND "+"数学成绩 >= "+mathmin;
String condition="SELECT * FROM students WHERE "+mCondition+" and "+eCondition;
rs=sql.executeQuery(condition);
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
out.print("<TD >"+rs.getString(1)+"</TD>");
out.print("<TD >"+rs.getString(2)+"</TD>");
out.print("<TD >"+rs.getInt("数学成绩")+"</TD>");
out.print("<TD >"+rs.getInt("英语成绩")+"</TD>");
out.print("<TD >"+rs.getInt("物理成绩")+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e)
{}
%>
</BODY>
</HTML>
5.3.5 排序查询
可以在SQL语句中使用ORDER BY子语句,对记录排序。在下面的例子中,使用SQL语句的ORDER BY子语句查询所同学的成绩,可以选择按3科的总分从低到高排列记录、按姓氏拼音排序或英语成绩排序。
例如,按总成绩排序查询的SQL语句:
SELECT * FROM student ORDER BY 数学成绩+英语成绩+物理成绩。
例子6(效果如图5.19、5.20所示)
Example5_6:
<%@ page contentType="text/html;charset=GB2312" %>
<HTML>
<BODY>
<P>查询成绩:
<Font size=1>
<FORM action="byname1.jsp" method=post name=form>
<INPUT type="radio" name="R" value="姓名">按姓氏排序
<INPUT type="radio" name="R" value="数学成绩+英语成绩+物理成绩">按总分排序
<INPUT type="radio" name="R" value="英语成绩">按英语排序
<BR> <Input type=submit name="g" value="提交">
</Form>
</BODY>
</HTML>
byname1.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% //获取提交的排序方式:
String name=request.getParameter("R");
if(name==null)
{name="";}
byte b[]=name.getBytes("ISO-8859-1");
name=new String(b);
String number,xingming;
Connection con=null;
Statement sql=null;
ResultSet rs=null;
int math,english,physics;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
String condition="SELECT * FROM students ORDER BY "+name;
rs=sql.executeQuery(condition);
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("<TH width=50>"+"总成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
number=rs.getString(1);
out.print("<TD >"+number+"</TD>");
xingming=rs.getString(2);
out.print("<TD >"+xingming+"</TD>");
math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
int total=math+english+physics;
out.print("<TH >"+total+"</TH>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e)
{ }
%>
</BODY>
</HTML>
5.3.6 分析结果集查询
通过分析结果集来输出记录。在下面的例子中查询所有姓王的同学的成绩,首先判断结果集中,姓氏字段的值是否是某个姓氏,然后输出全部该姓氏的同学的成绩。
例子7(效果如图5.21所示)
Example5_7.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<HTML>
<BODY>
<P>查询成绩:
<Font size=1>
<P>输入学生的姓氏:
<BR> <FORM action="byname2.jsp" method=post name=form>
<INPUT type="text" name="name" value="王">
<BR> <Input type=submit name="g" value="提交">
</Form>
</BODY>
</HTML>
byname2.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% //获取提交的姓氏:
String name=request.getParameter("name");
if(name==null)
{name="";
}
byte b[]=name.getBytes("ISO-8859-1");
name=new String(b);
String number,xingming;
Connection con=null;
Statement sql=null;
ResultSet rs=null;
int math,english,physics;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try{ con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
String condition="SELECT * FROM students" ;
rs=sql.executeQuery(condition);
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ number=rs.getString(1);
xingming=rs.getString(2);
if(xingming.startsWith("王"))
{ out.print("<TR>");
out.print("<TD >"+number+"</TD>");
out.print("<TD >"+xingming+"</TD>");
math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
}
out.print("</Table>");
con.close();
}
catch(SQLException e)
{ }
%>
</BODY>
</HTML>
5.3.7 使用统配符查询
可以用SQL语句操作符LIKE进行模式般配,使用“%”代替一个或多个字符,用一个下划线“_”代替一个字符。比如,下述语句查询姓氏是“王”的记录:
rs=sql.executeQuery("SELECT * FROM students WHERE 姓名 LIKE '王%' ");
请将上面的例子7改为通配符查询,查询所有姓氏是王的记录。
5.4 更新记录
我们可以使用SQL语句更新记录中字段的值
Statement对象调用方法:
public int executeUpdate(String sqlStatement);
通过参数sqlStatement指定的方式实现对数据库表中记录的字段值的更新,例如,下述语句将表students中王名同学的数学字段的值更新88:
executeUpdate("UPDATE students SET 数学成绩 = 88 WHERE 姓名='王名'");
注:你可以使用一个Statement对象进行更新和查询操作,但需要注意的是,当查询语句返回结果集后,没有立即输出结果集的记录,而接着执行了更新语句,那么结果集就不能输出记录了。要想输出记录就必须重新返回结果集。
在下面的例子8中,可以更新学生的各科的成绩。在Example5_8.jsp页面提交学生的姓名以及这个学生新的成绩到newResult.jsp页面,该页面负责更新记录的字段值。
例子8(效果如图5.22、5.23所示)
Example5_8.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY bgcolor=pink >
<Font size=1>
<FORM action="newResult.jsp" method=post>
输入要修改成绩的同学的姓名:<BR>
<Input type="text" name="name">
<BR>输入新的数学成绩:
<Input type="text" name="math">
<BR>输入新的英语成绩:
<Input type="text" name="english">
<BR>输入新的物理成绩:
<Input type="text" name="physics">
<BR><Input type="submit" name="b" value="提交更新">
<P>数据库更新前的数据记录是:
<% String name,number;
int math,physics,english;
Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try{ con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
rs=sql.executeQuery("SELECT * FROM students");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
number=rs.getString(1);
out.print("<TD >"+number+"</TD>");
name=rs.getString(2);
out.print("<TD >"+name+"</TD>");
math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {}
%>
</Font>
</BODY>
</HTML>
newResult.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY bgcolor=pink ><Font size=1>
<% //获取提交的姓名:
String name=request.getParameter("name");
if(name==null)
{name="";
}
byte b[]=name.getBytes("ISO-8859-1");
name=new String(b);
//获取提交的新的数学成绩:
String newMath=request.getParameter("math");
if(newMath==null)
{newMath="-100";
}
//获取提交的新的英语成绩:
String newEnglish=request.getParameter("english");
if(newEnglish==null)
{newEnglish="-100";
}
//获取提交的新的物理成绩:
String newPhysics=request.getParameter("physics");
if(newPhysics==null)
{newPhysics="-100";
}
Connection con=null;
Statement sql=null;
ResultSet rs=null;
String number,xingming;
int math,english,physics;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try {con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
String condition1=
"UPDATE students SET 数学成绩 = "+newMath+" WHERE 姓名="+"'"+name+"'" ,
condition2=
"UPDATE students SET 英语成绩 = "+newEnglish+" WHERE 姓名="+"'"+name+"'" ,
condition3=
"UPDATE students SET 物理成绩 = "+newPhysics+" WHERE 姓名="+"'"+name+"'" ;
//执行更新操作:
sql.executeUpdate(condition1);
sql.executeUpdate(condition2);
sql.executeUpdate(condition3);
//显示更新后的表中的记录:
%>
<P>更新后的表的记录:
<%
rs=sql.executeQuery("SELECT * FROM students");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{
out.print("<TR>");
number=rs.getString(1);
out.print("<TD >"+number+"</TD>");
xingming=rs.getString(2);
out.print("<TD >"+xingming+"</TD>");
math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e)
{ }
%>
</FONT>
</BODY>
</HTML>
5.5 添加记录
我们可以使用SQL语句添加新的记录,Statement对象调用方法:
public int executeUpdate(String sqlStatement);
通过参数sqlStatement指定的方式实现向数据库表中添加新记录,例如,下述语句将向表students中添加一条新的记录:(’199911’,’美丽家’,100,99,98)。
executeUpdate("INSERT INTO students VALUES (’199911’,’美丽家’,100,99,98)");
在下面的例子9中,可以添加新的记录。在Example5_9.jsp页面提交新的记录到newDatabase.jsp页面,该页面负责添加新的记录。
注:你可以使用一个Statement对象进行添加和查询操作,但需要注意的是,当查询语句返回结果集后,没有立即输出结果集的记录,而接着执行了添加语句,那么结果集就不能输出记录了。要想输出记录就必须重新返回结果集。
例子9(效果如图5.24、5.25所示)
Example5_9.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY bgcolor=pink >
<Font size=1>
<P>添加新的记录到数据库:
<FORM action="newDatabase.jsp" method=post>
同学学号:
<Input type="text" name="number">
<BR>同学姓名:
<Input type="text" name="name">
<BR>数学成绩:
<Input type="text" name="math">
<BR>英语成绩:
<Input type="text" name="english">
<BR>物理成绩:
<Input type="text" name="physics">
<BR><Input type="submit" name="b" value="提交添加">
<P>数据库添加记录前的数据记录是:
<% String name,number;
int math,physics,english;
Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:moon","sa","");
sql=con.createStatement();
rs=sql.executeQuery("SELECT * FROM students");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
number=rs.getString(1);
out.print("<TD >"+number+"</TD>");
name=rs.getString(2);
out.print("<TD >"+name+"</TD>");
math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {}
%>
</Font>
</BODY>
</HTML>
newDatabase.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY bgcolor=pink ><Font size=1>
<% //获取提交的学号:
String number=request.getParameter("number");
if(number==null)
{number="";
}
byte b[]=number.getBytes("ISO-8859-1");
number=new String(b);
//获取提交的姓名:
String name=request.getParameter("name");
if(name==null)
{name="";
}
byte c[]=name.getBytes("ISO-8859-1");
name=new String(c);
//获取提交的新的数学成绩:
String m=request.getParameter("math");
if(m==null)
{m="-100"; }
//获取提交的新的英语成绩:
String e=request.getParameter("english");
if(e==null)
{e="-100"; }
//获取提交的新的物理成绩:
String p=request.getParameter("physics");
if(p==null)
{p="-100"; }
Connection con=null;
Statement sql=null;
ResultSet rs=null;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); }
catch(ClassNotFoundException event){}
try {con=DriverManager.getConnection("jdbc:odbc:moon","sa","");
sql=con.createStatement();
String condition=
"INSERT INTO students VALUES"+"("+"'"+number+"','"+name+"',"+m+","+e+","+p+")";
sql.executeUpdate(condition); //执行添加操作:
//显示添加新记录后表中的记录:
%>
<P>添加新记录后的表:
<%
rs=sql.executeQuery("SELECT * FROM students ORDER BY 学号 ");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
String n=rs.getString(1);
out.print("<TD >"+n+"</TD>");
String xingming=rs.getString(2);
out.print("<TD >"+xingming+"</TD>");
int math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
int english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
int physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException event)
{ }
%>
</FONT>
</BODY>
</HTML>
5.6 删除记录
我们可以使用SQL语句删除记录,Statement对象调用方法:
public int executeUpdate(String sqlStatement);
通过参数sqlStatement指定的方式删除数据库表中的记录,例如,下述语句将删除学号是199904的记录:
executeUpdate("DELETE FROM students WHERE 学号 = ‘199904’ ");
在下面的例子10中,可以删除已有的记录。在Example5_10.jsp页面提交要被删除的记录的字段值到delete.jsp页面,delete.jsp页面负责删除相应的记录。
注:你可以使用一个Statement对象进行删除和查询操作,但需要注意的是,当查询语句返回结果集后,没有立即输出结果集的记录,而接着执行了删除语句,那么结果集就不能输出记录了。要想输出记录就必须重新返回结果集。
例子10(效果如图5.26、5.27所示)
Example5_10.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY bgcolor=pink >
<Font size=1>
<P>删除记录:
<FORM action="delete.jsp" method=post>
输入被删除记录的学号:
<Input type="text" name="number">
<BR>
<BR><Input type="submit" name="b" value="提交删除">
</FORM>
<P>数据库删除前的数据记录是:
<% String name,number;
int math,physics,english;
Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
rs=sql.executeQuery("SELECT * FROM students");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
number=rs.getString(1);
out.print("<TD >"+number+"</TD>");
name=rs.getString(2);
out.print("<TD >"+name+"</TD>");
math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {}
%>
</Font>
</BODY>
</HTML>
delete.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY bgcolor=pink ><Font size=1>
<% //获取提交的学号:
String number=request.getParameter("number");
if(number==null)
{number="";
}
byte b[]=number.getBytes("ISO-8859-1");
number=new String(b);
Connection con=null;
Statement sql=null;
ResultSet rs=null;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException event){}
try {con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=con.createStatement();
//删除操作:
String deleteAll="DELETE FROM students WHERE 学号"+" = "+"'"+number+"'";
sql.executeUpdate(deleteAll);
%>
<P>删除记录后的表:
<%
rs=sql.executeQuery("SELECT * FROM students ORDER BY 学号 ");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
String n=rs.getString(1);
out.print("<TD >"+n+"</TD>");
String xingming=rs.getString(2);
out.print("<TD >"+xingming+"</TD>");
int math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
int english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
int physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException event)
{out.print(""+event);
}
%>
</FONT>
</BODY>
</HTML>
5.7 分页显示记录
我们简单地实现数据库表中记录的分页显示。
假设总记录数为m,每页显示数量是n,那么总页数的计算公式是:
(1) 如果m除以n的余数大于0,总页数等于m除以n的商加1;
(2) 如果m除以n的余数等于0,总页数等于m除以n的商。
即
总页数=(m%n)==0?(m/n):(m/n+1);
如果准备显示第p页的内容,应当把游标移动到第(p-1)*n+1条记录处。
showByPage.jsp:(效果如图5.28所示)
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<%! int pageSize=3; //每页显示的记录数。
int pageCount=0; //分页后的总页数。
%>
<%-- 客户通过表单提交欲要显示的页码数--%>
<FORM action="" method=get >
输入页码数<Input Type=text name=showPage size=4 >
<Input Type=submit name=g value=提交>
</FORM>
<% Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:sun","sa","");
sql=
con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
//返回可滚动的结果集:
rs=sql.executeQuery("SELECT * FROM students");
//将游标移动到最后一行:
rs.last();
//获取最后一行的行号:
int lastRow=rs.getRow();
//计算分页后的总页数:
pageCount=(lastRow%pageSize==0)?(lastRow/pageSize):(lastRow/pageSize+1);
//当前显示的初始页数:
int showPage=1;
//告知客户总页数:
%>
<P> 共有<%=pageCount%>页
<BR>每页显示<%=pageSize%>条记录.
<% //获取客户想要显示的页数:
String integer=request.getParameter("showPage");
if(integer==null)
{ integer="1";
}
try {showPage=Integer.parseInt(integer);
}
catch(NumberFormatException e)
{showPage=1;
}
if(showPage<=1)
{showPage=1;
}
if(showPage>=pageCount)
{showPage=pageCount;
}
%>
<BR>目前显示第<%=showPage%>页
<% //如果要显示第showPage页,那么游标应移到posion的值是:
int posion=(showPage-1)*pageSize+1;
rs.absolute(posion); // 设置游标的位置
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
for (int i=1;i<=pageSize;i++)
{ out.print("<TR>");
out.print("<TD >"+rs.getString(1)+"</TD>");
out.print("<TD >"+rs.getString(2)+"</TD>");
out.print("<TD >"+rs.getInt("数学成绩")+"</TD>");
out.print("<TD >"+rs.getInt("英语成绩")+"</TD>");
out.print("<TD >"+rs.getInt("物理成绩")+"</TD>");
out.print("</TR>") ;
rs.next();
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {}
%>
</BODY>
</HTML>
5.8 连接数据库的其它方式
5.8.1 连接Oracle数据库
我们也可以通过JDBC-ODBC桥接器和Oracle数据库建立连接,但这种连接的质量依赖于ODBC。下面介绍通过直接加载Oracle数据库驱动程序来连接数据库的方法。
安装Oracle后,找到目录:Oracle/ora81/jdbc中的文件:classes12.zip;将该文件拷贝到你的JDK的如下目录中:
f:/jdk1.3/jre/lib/ext
并将classes.zip重新命名为classes.jre或classes.jar。
通过如下的两个步骤和一个Oracle数据库建立连接:
(1)加载驱动程序:
Class.forName("oracle.jdbc.driver.OracleDriver");
(2)建立连接:
Connection conn=
DriverManager.getConnection( “jdbc:oracle:thin:@主机host:端口号:数据库名”, “用户名”, “密码”);
例子11(效果如图5.29所示)
Example5_11.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% Connection con=null;
Statement sql=null;
ResultSet rs=null;
try{Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException e){}
try
{ con=
DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.35:1521:Lea","scott","tiger");
sql=con.createStatement();
rs=sql.executeQuery("select * from emp");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"EMPNO");
out.print("<TH width=50>"+"Ename");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
int n=rs.getInt(1);
out.print("<TD >"+n+"</TD>");
String e=rs.getString(2);
out.print("<TD >"+e+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {out.print(""+e1);}
%>
</BODY>
</HTML>
注:如果出现无法找到OracleDriver异常,请首先检查JDK的目录:jdk/jre/lib/ext中是否有classes12.jre文件,如果有该文件,仍出现OracleDriver异常,尝试将下列路径加入环境变量
jdk/jre/lib/ext/classes.jre
5.8.2 连接MySql数据库
可以到地址:http://www.wordsercer.com/mm.mysql下载驱动程序,然后安装到某个盘,比如C:。
将下列路径加入环境变量
C:/mm.mysql.jdbc-2.0pre5。
与一个Mysal数据库建立连接有如下2步:
(1)加载驱动程序:
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
(2)建立连接:
Connection conn=DriverManager.getConnection(”jdbc:mysql://host:Port:数据库名”,”用户名”,”密码”);
5.9 查询Excel电子表格
有时需要查询Excel或更新删除Excel电子表格的内容,可以通过JDBC-ODBC桥接器访问Excel表格。访问Exel表格和我们访问其它的数据库有所不同,结合例子讲述如下:
假设有电子表格:goods.xls,见下图5.30。
(1) 设置数据源:
设置数据源的名字是star,为数据源选择的驱动程序是:Microsoft Excel Driver
(2) 选择表:
与访问其它数据库不同的是,我们必须在电子表格中选出一工作区作为连接时使用的表。
在Excel电子表格中拖动鼠标选出范围,如下图5.31所示。然后在Excel菜单中选择插入→名称→定义,给选中的工作区命名(这一工作区的名称将作为连接时使用的表名)。如图5.32所示。
这样我们就创建了一个名字是“品名”、有3个字段的表。现在就可以在JSP中查询、更新、删除这个表中的记录了。
下面的例子12查询了“品名”表中的全部记录。
例子12(效果如图5.33所示)
Example5_12.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<% Connection con;
Statement sql;
ResultSet rs;
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
try { con=DriverManager.getConnection("jdbc:odbc:star","","");
sql=con.createStatement();
rs=sql.executeQuery("SELECT * FROM 品名 ");
out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"品名");
out.print("<TH width=50>"+"单位");
out.print("<TH width=50>"+"单价");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
String name=rs.getString(1);
out.print("<TD >"+name+"</TD>");
String unit=rs.getString(2);
out.print("<TD >"+unit+"</TD>");
String unitprice=rs.getString(3);
out.print("<TD >"+unitprice+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
con.close();
}
catch(SQLException e1) {}
%>
</BODY>
</HTML>
5.10 使用同步连接
数据库操作中,建立连接是耗时最大的操作之一。如果客户访问的是同一数据库,那么,为每个客户都建立一个连接是不合理的。我们已经知道,在“<%!”和“%>”之间声明的变量在整个JSP页面内都有效,因为JSP引擎将JSP页面转译成Java文件时,将这些变量作为类的成员变量。这些变量的内存空间直到服务器关闭才释放。当多个客户请求一个JSP页面时,JSP引擎为每个客户启动一个线程而不是启动一个进程,这些线程由Web服务器进程来管理,它们共享JSP页面的成员变量。在处理多线程问题时,可以将线程共享的变量放入一个synchronized块,或将修改该变量的方法用synchronized来修饰,这样,当一个客户用synchronized块或synchronized方法修改一个共享变量时,其它线程就必须等待,直到该线程执行完该方法或同步块。这样,我们可以把Connection对象作为一个成员变量被所有的客户共享,也就是说第一个访问数据库的客户负责建立连接,以后所有的客户共享这个连接,每个客户都不要关闭这个共享的连接。
例子13(效果如图5.34、5.35所示)
Example5_13.jsp:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<HTML>
<BODY>
<%! //声明一个共享的连接对象:
Connection con=null;
%>
<% Statement sql=null;
ResultSet rs=null;
//第一个客户负责建立连接对象:
if(con==null)
{ try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e)
{out.print(e);
}
try {con=DriverManager.getConnection("jdbc:odbc:moon","sa","");
sql=con.createStatement();
rs =sql.executeQuery("SELECT * FROM students");
out.print("i am first");
}
catch(SQLException e)
{out.print(e);
}
}
else //其它客户通过同步块使用这个连接:
{ synchronized(con)
{ try { sql=con.createStatement();
rs =sql.executeQuery("SELECT * FROM students");
out.print("i am not first");
}
catch(SQLException e)
{out.print(e);
}
}
}
try
{ out.print("<Table Border>");
out.print("<TR>");
out.print("<TH width=100>"+"学号");
out.print("<TH width=100>"+"姓名");
out.print("<TH width=50>"+"数学成绩");
out.print("<TH width=50>"+"英语成绩");
out.print("<TH width=50>"+"物理成绩");
out.print("</TR>");
while(rs.next())
{ out.print("<TR>");
String number=rs.getString(1);
out.print("<TD >"+number+"</TD>");
String name=rs.getString(2);
out.print("<TD >"+name+"</TD>");
int math=rs.getInt("数学成绩");
out.print("<TD >"+math+"</TD>");
int english=rs.getInt("英语成绩");
out.print("<TD >"+english+"</TD>");
int physics=rs.getInt("物理成绩");
out.print("<TD >"+physics+"</TD>");
out.print("</TR>") ;
}
out.print("</Table>");
}
catch(SQLException e1) {}
%>
</BODY>
</HTML>
|