如何利用jdbc发送sql语句?
statement对象用于将sql语句发送到数据库中。实际上有三种statement对象,它们都作为在给定连接上执行sql语句的包容器:statement、preparedstatement(它从statement继承而来)和callablestatement(它从preparedstatement继承而来)。它们都专用于发送特定类型的sql语句:statement对象用于执行不带参数的简单sql语句;preparedstatement对象用于执行带或不带in参数的预编译sql语句;callablestatement对象用于执行对数据库已存储过程的调用。
statement接口提供了执行语句和获取结果的基本方法;preparedstatement接口添加了处理in参数的方法;而callablestatement添加了处理out参数的方法。
1. 创建statement对象
建立了到特定数据库的连接之后,就可用该连接发送sql语句。statement对象用connection的方法createstatement创建,如下列代码段中所示:
connection con = drivermanager.getconnection(url,"sunny","");
statement stmt = con.createstatement();
为了执行statement对象,被发送到数据库的sql语句将被作为参数提供给statement的方法:
resultset rs = stmt.executequery("select a,b,c from table2");
2. 使用statement对象执行语句
statement接口提供了三种执行sql语句的方法:executequery、executeupdate和execute。使用哪一个方法由sql语句所产生的内容决定。
方法executequery用于产生单个结果集的语句,例如select语句。方法executeupdate用于执行insert、update或delete语句以及sql ddl(数据定义语言)语句,例如create table和drop table。insert、update或delete语句的效果是修改表中零行或多行中的一列或多列。executeupdate的返回值是一个整数,指示受影响的行数(即更新计数)。对于create table或drop table等不操作行的语句,executeupdate的返回值总为零。
执行语句的所有方法都将关闭所调用的statement对象的当前打开结果集(如果存在)。这意味着在重新执行statement对象之前,需要完成对当前resultset对象的处理。应注意,继承了statement接口中所有方法的preparedstatement接口都有自己的executequery、executeupdate和execute方法。statement对象本身不包含sql语句,因而必须给statement.execute方法提供sql语句作为参数。preparedstatement对象并不需要sql语句作为参数提供给这些方法,因为它们已经包含预编译sql语句。
callablestatement对象继承这些方法的preparedstatement形式。对于这些方法的preparedstatement或callablestatement版本,使用查询参数将抛出sqlexception。
3. 语句完成
当连接处于自动提交模式时,其中所执行的语句在完成时将自动提交或还原。语句在已执行且所有结果返回时,即认为已完成。对于返回一个结果集的executequery方法,在检索完resultset对象的所有行时该语句完成。对于方法executeupdate,当它执行时语句即完成。但在少数调用方法execute的情况中,在检索所有结果集或它生成的更新计数之后语句才完成。
有些dbms将已存储过程中的每条语句视为独立的语句;而另外一些则将整个过程视为一个复合语句。在启用自动提交时,这种差别就变得非常重要,因为它影响什么时候调用commit方法。在前一种情况中,每条语句单独提交;在后一种情况中,所有语句同时提交。
4. 关闭statement对象
statement对象将由java垃圾收集程序自动关闭。而作为一种好的编程风格,应在不需要statement对象时显式地关闭它们。这将立即释放dbms资源,有助于避免潜在的内存问题。
5. 使用方法execute
execute方法应该仅在语句能返回多个resultset对象、多个更新计数或resultset对象与更新计数的组合时使用。当执行某个已存储过程或动态执行未知sql字符串(即应用程序程序员在编译时未知)时,有可能出现多个结果的情况,尽管这种情况很少见。例如,用户可能执行一个已存储过程,并且该已存储过程可执行更新,然后执行选择,再进行更新,再进行选择,等等。通常使用已存储过程的人应知道它所返回的内容。
因为方法execute处理非常规情况,所以获取其结果需要一些特殊处理并不足为怪。例如,假定已知某个过程返回两个结果集,则在使用方法execute执行该过程后,必须调用方法getresultset获得第一个结果集,然后调用适当的getxxx方法获取其中的值。要获得第二个结果集,需要先调用getmoreresults方法,然后再调用getresultset方法。如果已知某个过程返回两个更新计数,则首先调用方法getupdatecount,然后调用getmoreresults,并再次调用getupdatecount。
对于不知道返回内容,则情况更为复杂。如果结果是resultset对象,则方法execute返回true;如果结果是javaint,则返回false。如果返回int,则意味着结果是更新计数或执行的语句是dl命令。在调用方法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("rows changed="+count);
stmt.getmoreresults();
continue;
}
if(rowcount==0){//ddl命令或0个更新
system.out.println("no rows changed or statement was ddl command");
stmt.getmoreresults();
continue;
}
//执行到这里,证明有一个结果集
//或没有其它结果
resultset rs=stmt.getresultset();
if(rs!=null){
…//使用元数据获得关于结果集列的信息
while(rs.next()){
…//处理结果
stmt.getmoreresults();
continue;
}
break;//没有其它结果
