教 学 活 动 首 页
基 本 内 容 |
第 5 章 JSP 中使用数据库 |
教学目的与要求:通过本章的学习让学生了解数据源的设置过程;理解JDBC-ODBC 桥接器的工作原理,连接数据库的其他方式,查询 Excel 电子表格;掌握查询记录,更新记录,添加记录,删除记录的操作方法;并能实现分页显示记录,使用同步连接。 |
教学内容: 5.1 数据源 5.2 JDBC-ODBC 桥接器 5.3 查询记录 5.4 更新记录 5.5 添加记录 5.6 删除记录 5.7 分页显示记录 5.8 连接数据库的其他方式 5.9 查询 Excel 电子表格 5.10 使用同步连接 |
教学基本要求: 了解:数据源的设置 理解:JDBC-ODBC 桥接器,连接数据库的其他方式,查询 Excel 电子表格 掌握:查询记录,更新记录,添加记录,删除记录 应用:分页显示记录,使用同步连接 |
教学重点教学难点: JDBC-ODBC 桥接器,查询记录,更新记录,添加记录,删除记录,分页显示记录,使用同步连接 |
教学方法: 教学手段:多媒体教学和计算机程序演示 |
教学小结: (见教学进程) |
作业与思考:见课后习题 |
课后记载:
|
教 学 进 程
第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.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表里的包含全部字段的记录。
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:端口号:数据库名”, “用户名”, “密码”);
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对象作为一个成员变量被所有的客户共享,也就是说第一个访问数据库的客户负责建立连接,以后所有的客户共享这个连接,每个客户都不要关闭这个共享的连接。
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> |