JDBCTM 指南:入门4 - Statement

4-Statement

本概述是从《JDBCTMDatabaseAccessfromJavaTM:ATutorialandAnnotatedReference》这本书中摘引来的。JavaSoft目前正在准备这本书。这是一本教程,同时也是JDBC的重要参考手册,它将作为Java系列的组成部份在1997年春季由Addison-Wesley出版公司出版。

4.1概述

Statement对象用于将SQL语句发送到数据库中。实际上有三种Statement对象,它们都作为在给定连接上执行SQL语句的包容器:Statement、PreparedStatement(它从Statement继承而来)和CallableStatement(它从PreparedStatement继承而来)。它们都专用于发送特定类型的SQL语句:Statement对象用于执行不带参数的简单SQL语句;PreparedStatement对象用于执行带或不带IN参数的预编译SQL语句;CallableStatement对象用于执行对数据库已存储过程的调用。

Statement接口提供了执行语句和获取结果的基本方法。PreparedStatement接口添加了处理IN参数的方法;而CallableStatement添加了处理OUT参数的方法。

4.1.1创建Statement对象

建立了到特定数据库的连接之后,就可用该连接发送SQL语句。Statement对象用Connection的方法createStatement创建,如下列代码段中所示:

Connectioncon=DriverManager.getConnection(url,"sunny","");

Statementstmt=con.createStatement();

为了执行Statement对象,被发送到数据库的SQL语句将被作为参数提供给Statement的方法:

ResultSetrs=stmt.executeQuery("SELECTa,b,cFROMTable2");

4.1.2使用Statement对象执行语句

Statement接口提供了三种执行SQL语句的方法:executeQuery、executeUpdate和execute。使用哪一个方法由SQL语句所产生的内容决定。

方法executeQuery用于产生单个结果集的语句,例如SELECT语句。

方法executeUpdate用于执行INSERT、UPDATE或DELETE语句以及SQLDDL(数据定义语言)语句,例如CREATETABLE和DROPTABLE。INSERT、UPDATE或DELETE语句的效果是修改表中零行或多行中的一列或多列。executeUpdate的返回值是一个整数,指示受影响的行数(即更新计数)。对于CREATETABLE或DROPTABLE等不操作行的语句,executeUpdate的返回值总为零。

方法execute用于执行返回多个结果集、多个更新计数或二者组合的语句。因为多数程序员不会需要该高级功能,所以本概述后面将在单独一节中对其进行介绍。

执行语句的所有方法都将关闭所调用的Statement对象的当前打开结果集(如果存在)。这意味着在重新执行Statement对象之前,需要完成对当前ResultSet对象的处理。

应注意,继承了Statement接口中所有方法的PreparedStatement接口都有自己的executeQuery、executeUpdate和execute方法。Statement对象本身不包含SQL语句,因而必须给Statement.execute方法提供SQL语句作为参数。PreparedStatement对象并不将SQL语句作为参数提供给这些方法,因为它们已经包含预编译SQL语句。CallableStatement对象继承这些方法的PreparedStatement形式。对于这些方法的PreparedStatement或CallableStatement版本,使用查询参数将抛出SQLException。

4.1.3语句完成

当连接处于自动提交模式时,其中所执行的语句在完成时将自动提交或还原。语句在已执行且所有结果返回时,即认为已完成。对于返回一个结果集的executeQuery方法,在检索完ResultSet对象的所有行时该语句完成。对于方法executeUpdate,当它执行时语句即完成。但在少数调用方法execute的情况中,在检索所有结果集或它生成的更新计数之后语句才完成。

有些DBMS将已存储过程中的每条语句视为独立的语句;而另外一些则将整个过程视为一个复合语句。在启用自动提交时,这种差别就变得非常重要,因为它影响什么时候调用commit方法。在前一种情况中,每条语句单独提交;在后一种情况中,所有语句同时提交。

4.1.4关闭Statement对象

Statement对象将由Java垃圾收集程序自动关闭。而作为一种好的编程风格,应在不需要Statement对象时显式地关闭它们。这将立即释放DBMS资源,有助于避免潜在的内存问题。

4.1.5Statement对象中的SQL转义语法

Statement可包含使用SQL转义语法的SQL语句。转义语法告诉驱动程序其中的代码应该以不同方式处理。驱动程序将扫描任何转义语法,并将它转换成特定数据库可理解的代码。这使得转义语法与DBMS无关,并允许程序员使用在没有转义语法时不可用的功能。

转义子句由花括号和关键字界定:

{keyword...parameters...}

该关键字指示转义子句的类型,如下所示。

escape表示LIKE转义字符

字符“%”和“_”类似于SQLLIKE子句中的通配符(“%”匹配零个或多个字符,而“_”则匹配一个字符)。为了正确解释它们,应在其前面加上反斜杠(“\”),它是字符串中的特殊转义字符。在查询末尾包括如下语法即可指定用作转义字符的字符:

{escape´escape-character´}

例如,下列查询使用反斜杠字符作为转义字符,查找以下划线开头的标识符名:

stmt.executeQuery("SELECTnameFROMIdentifiers

WHEREIdLIKE`\_%´{escape`\´};

fn表示标量函数

几乎所有DBMS都具有标量值的数值、字符串、时间、日期、系统和转换函数。要使用这些函数,可使用如下转义语法:关键字fn后跟所需的函数名及其参数。例如,下列代码调用函数concat将两个参数连接在一起:

{fnconcat("Hot","Java")};

可用下列语法获得当前数据库用户名:

{fnuser()};

标量函数可能由语法稍有不同的DBMS支持,而它们可能不被所有驱动程序支持。各种DatabaseMetaData方法将列出所支持的函数。例如,方法getNumericFunctions返回用逗号分隔的数值函数列表,而方法getStringFunctions将返回字符串函数,等等。

驱动程序将转义函数调用映射为相应的语法,或直接实现该函数。

d、t和ts表示日期和时间文字

DBMS用于日期、时间和时间标记文字的语法各不相同。JDBC使用转义子句支持这些文字的语法的ISO标准格式。驱动程序必须将转义子句转换成DBMS表示。

例如,可用下列语法在JDBCSQL语句中指定日期:

{d`yyyy-mm-dd´}

在该语法中,yyyy为年代,mm为月份,而dd则为日期。驱动程序将用等价的特定于DBMS的表示替换这个转义子句。例如,如果´28-FEB-99´符合基本数据库的格式,则驱动程序将用它替换{d1999-02-28}。

对于TIME和TIMESTAMP也有类似的转义子句:

{t`hh:mm:ss´}

{ts`yyyy-mm-ddhh:mm:ss.f...´}

TIMESTAMP中的小数点后的秒(.f...)部分可忽略。

call或?=call表示已存储过程

如果数据库支持已存储过程,则可从JDBC中调用它们,语法为:

{callprocedure_name[(?,?,...)]}

或(其中过程返回结果参数):

{?=callprocedure_name[(?,?,...)]}

方括号指示其中的内容是可选的。它们不是语法的必要部分。

输入参数可以为文字或参数。有关详细信息,参见JDBC指南中第7节,“CallableStatement”。

可通过调用方法DatabaseMetaData.supportsStoredProcedures检查数据库是否支持已存储过程。

oj表示外部连接

外部连接的语法为

{ojouter-join}

其中outer-join形式为

tableLEFTOUTERJOIN{table/outer-join}ONsearch-condition

外部连接属于高级功能。有关它们的解释可参见SQL语法。JDBC提供了三种DatabaseMetaData方法用于确定驱动程序支持哪些外部连接类型:supportsOuterJoins、supportsFullOuterJoins和supportsLimitedOuterJoins。

方法Statement.setEscapeProcessing可打开或关闭转义处理;缺省状态为打开。当性能极为重要时,程序员可能想关闭它以减少处理时间。但通常它将出于打开状态。应注意:setEscapeProcessing不适用于PreparedStatement对象,因为在调用该语句前它就可能已被发送到数据库。有关预编译的信息,参见PreparedStatement。

4.1.6使用方法execute

execute方法应该仅在语句能返回多个ResultSet对象、多个更新计数或ResultSet对象与更新计数的组合时使用。当执行某个已存储过程或动态执行未知SQL字符串(即应用程序程序员在编译时未知)时,有可能出现多个结果的情况,尽管这种情况很少见。例如,用户可能执行一个已存储过程(使用CallableStatement对象-参见第135页的CallableStatement),并且该已存储过程可执行更新,然后执行选择,再进行更新,再进行选择,等等。通常使用已存储过程的人应知道它所返回的内容。

因为方法execute处理非常规情况,所以获取其结果需要一些特殊处理并不足为怪。例如,假定已知某个过程返回两个结果集,则在使用方法execute执行该过程后,必须调用方法getResultSet获得第一个结果集,然后调用适当的getXXX方法获取其中的值。要获得第二个结果集,需要先调用getMoreResults方法,然后再调用getResultSet方法。如果已知某个过程返回两个更新计数,则首先调用方法getUpdateCount,然后调用getMoreResults,并再次调用getUpdateCount。

对于不知道返回内容,则情况更为复杂。如果结果是ResultSet对象,则方法execute返回true;如果结果是Javaint,则返回false。如果返回int,则意味着结果是更新计数或执行的语句是DDL命令。在调用方法execute之后要做的第一件事情是调用getResultSet或getUpdateCount。调用方法getResultSet可以获得两个或多个ResultSet对象中第一个对象;或调用方法getUpdateCount可以获得两个或多个更新计数中第一个更新计数的内容。

当SQL语句的结果不是结果集时,则方法getResultSet将返回null。这可能意味着结果是一个更新计数或没有其它结果。在这种情况下,判断null真正含义的唯一方法是调用方法getUpdateCount,它将返回一个整数。这个整数为调用语句所影响的行数;如果为-1则表示结果是结果集或没有结果。如果方法getResultSet已返回null(表示结果不是ResultSet对象),则返回值-1表示没有其它结果。也就是说,当下列条件为真时表示没有结果(或没有其它结果):

((stmt.getResultSet()==null)&&(stmt.getUpdateCount()==-1))

如果已经调用方法getResultSet并处理了它返回的ResultSet对象,则有必要调用方法getMoreResults以确定是否有其它结果集或更新计数。如果getMoreResults返回true,则需要再次调用getResultSet来检索下一个结果集。如上所述,如果getResultSet返回null,则需要调用getUpdateCount来检查null是表示结果为更新计数还是表示没有其它结果。

当getMoreResults返回false时,它表示该SQL语句返回一个更新计数或没有其它结果。因此需要调用方法getUpdateCount来检查它是哪一种情况。在这种情况下,当下列条件为真时表示没有其它结果:

((stmt.getMoreResults()==false)&&(stmt.getUpdateCount()==-1))

下面的代码演示了一种方法用来确认已访问调用方法execute所产生的全部结果集和更新计数:

stmt.execute(queryStringWithUnknownResults);

while(true){

introwCount=stmt.getUpdateCount();

if(rowCount>0){//它是更新计数

System.out.println("Rowschanged="+count);

stmt.getMoreResults();

continue;

}

if(rowCount==0){//DDL命令或0个更新

System.out.println("NorowschangedorstatementwasDDL

command");

stmt.getMoreResults();

continue;

}

//执行到这里,证明有一个结果集

//或没有其它结果

ResultSetrs=stmt.getResultSet;

if(rs!=null){

...//使用元数据获得关于结果集列的信息

while(rs.next()){

...//处理结果

stmt.getMoreResults();

continue;

}

break;//没有其它结果 

相关推荐