9.5.2、预编译方式执行SQL语句PreparedStatement
由于Statement对象在每次执行SQL语句时都将该语句传给数据库,如果需要多次执行同一条SQL语句时,这样将导致执行效率特别低,此时可以采用PreparedStatement对象来封装SQL语句。如果数据库支持预编译,它可以将SQL语句传给数据库作预编译,以后每次执行该SQL语句时,可以提高访问速度;但如果数据库不支持预编译,将在语句执行时才传给数据库,其效果类同于Statement对象。
另外PreparedStatement对象的SQL语句还可以接收参数,可以用不同的输入参数来多次执行编译过的语句,较Statement灵活方便(详见后文介绍)。
1、创建PreparedStatement对象:从一个Connection对象上可以创建一个PreparedStatement对象,在创建时可以给出预编译的SQL语句。
PreparedStatement pstmt=con.prepareStatement("select * from DBTableName");
2、执行SQL语句:可以调用executeQuery()来实现,但与Statement方式不同的是,它没有参数,因为在创建PreparedStatement对象时已经给出了要执行的SQL语句,系统并进行了预编译。
ResultSet rs=pstmt.executeQuery(); // 该条语句可以被多次执行
3、关闭PreparedStatement
pstmt.close(); //其实是调用了父类Statement类中的close()方法
9.5.3、执行存储过程CallableStatement
CallableStatement类是PreparedStatement类的子类,因此可以使用在PreparedStatement类及Statement类中的方法,主要用于执行存储过程。
1、创建CallableStatement对象:使用Connection类中的prepareCall方法可以创建一个CallableStatement对象,其参数是一个String对象,一般格式为:
不带输入参数的存储过程“{call 存储过程名()}”。
带输入参数的存储过程“{call存储过程名(?, ?)}”
带输入参数并有返回结果参数的存储过程“{? = call 存储过程名(?, ?, ...)}”
CallableStatement cstmt=con.prepareCall("{call Query1()}");
2、执行存储过程:可以调用executeQuery()方法来实现。
ResultSet rs=cstmt.executeQuery();
3、关闭CallableStatement
cstmt.close(); //其实是调用了父类Statement类中的close()方法
(6)检索记录集以获得当前记录集中的某一记录的各个字段的值
9.5.4、ResultSet对象:
① 执行完毕SQL语句后,将返回一个ResultSet类的对象,它包含所有的查询结果。但对ResultSet类的对象方式依赖于光标(Cursor)的类型,而对每一行中的各个列,可以按任何顺序进行处理(当然,如果按从左到右的顺序对各列进行处理可以获得较高的执行效率);
ResultSet类中的Course方式主要有:
ResultSet.TYPE_FORWARD_ONLY(为缺省设置):光标只能前进不能后退,也就是只能从第一个一直移动到最后一个。
ResultSet.TYPE_SCROLL_SENSITIVE:允许光标前进或后退并感应到其它ResultSet的光标的移动情形。
ResultSet.TYPE_SCROLL_INSENSITIVE:允许光标前进或后退并不能感应到其它ResultSet的光标的移动情形。
ResultSet类中的数据是否允许修改主要有:
ResultSet.CONCUR_READ_ONLY(为缺省设置):表示数据只能只读,不能更改。
ResultSet.CONCUR_UPDATABLE:表示数据允许被修改。
可以在创建Statement或PreparedStatement对象时指定ResultSet的这两个特性。
Statement stmt=con.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
或
PreparedStatement pstmt=con.PrepareStatement("insert into bookTable values (?,?,?)",
ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
② ResultSet类的对象维持一个指向当前行的指针,利用ResultSet类的next()方法可以移动到下一行(在JDBC中,Java程序一次只能看到一行数据),如果next()的返回值为false,则说明已到记录集的尾部。另外JDBC也没有类似ODBC 的书签功能的方法。
③ 利用ResultSet类的getXXX()方法可以获得某一列的结果,其中XXX代表JDBC中的Java数据类型,如 getInt()、getString()、getDate()等。访问时需要指定要检索的列(可以采用 int值作为列号(从1开始计数)或指定列(字段)名方式,但字段名不区别字母的大小写)。
while(rs.next())
{
String name=rs.getString("Name"); //采用“列名”的方式访问数据
int age=rs.getInt("age");
float wage=rs.getFloat("wage");
String homeAddress=rs.getString(4); //采用“列号”的方式访问数据
}
9.5.5、数据转换
利用ResultSet类的getXXX()方法可以实现将ResultSet中的SQL数据类型转换为它所返回的Java数据类型。
9.5.6、NULL结果值
要确定给定结果值是否是JDBC NULL,必须先读取该列,然后使用ResultSet.wasNull
方法检查该次读取是否返回JDBC NULL。
当使用ResultSet.getXXX方法读取JDBC NULL时,方法wasNull将返回下列值之一:
(1)Javanull值
对于返回Java对象的getXXX方法(例如getString、getBigDecimal、getBytes、getDate、getTime、getTimestamp、getAsciiStream、getUnicodeStream、getBinaryStream、getObject等)。
(2)零值:对于getByte、getShort、getInt、getLong、getFloat和getDouble。
(3)false值:对于getBoolean
9.5.6、获得结果集中的结构信息:利用ResultSet类的getMetaData()方法来获得结果集中的一些结构信息(主要提供用来描述列的数量、列的名称、列的数据类型。利用ResulSetMetaData类中的方法)。
ResultsetMetaData rsmd=rs.getMetaData();
rsmd.getColumnCount(); //返回结果集中的列数
rsmd.getColumnLabel(1); //返回第一列的列名(字段名)
例如:
Statement stmt=con.createStatement();
ResultSet rs=stmt.executeQuery("select * from TableName");
for(int i=1; i<=rs.getMetaData().getColumnCount(); i++) //跟踪显示各个列的名称
{
System.out.print(rs. getColumnName (i)+"\t");
}
while(rs.next())
{ //跟踪显示各个列的值
for(int j=1; j<=rs.getMetaData().getColumnCount(); j++)
{
System.out.print(rs.getObject(j)+"\t");
}
}