statement与resultset的对应关系

时间:2022-03-10 03:21:22


问题描述:

1,Connection是Statement的工厂,一个Connection可以生产多个Statement。

2,PreparedStatement,Statement是ResultSet的工厂,一个PreparedStatement,Statement却只能对应一个ResultSet(它们是一一对应的关系),但是同一个PreparedStatement和Statement可以及连续执行executeUpdate,execute除了返回ResultSet。

所以在一段程序里要用多个ResultSet的时候,必须再Connection中获得多个Statement,然后一个Statement对应一个ResultSet。在获取待生成的静态报表时采用连接数据库后创建了Statement对象并调用executeQuery(sql)方法返回ResultSet结果集,然后循环取出相应的记录。山寨测试代码如下:
  1. import java.sql.Connection;  
  2. import java.sql.DriverManager;  
  3. import java.sql.ResultSet;  
  4. import java.sql.Statement;  
  5. import java.util.ArrayList;  
  6. public class ResultSetTest {  
  7.   
  8.      public static void main(String[] args) {  
  9.           
  10.     String sql1=" select * from LKG_SR_EXCEL_TASK ";          
  11.         Connection conn=null;  
  12.     Statement stmt=null;  
  13.     ResultSet rs=null;  
  14.     ResultSet rsProc=null;  
  15.           
  16.     try{  
  17.           Class.forName("oracle.jdbc.driver.OracleDriver");  
  18.           conn=DriverManager.getConnection("jdbc:oracle:thin:@192.168.23.45:1521:ORABI","portal","portal123");  
  19.             
  20.           stmt=conn.createStatement();  
  21.           rs=stmt.executeQuery(sql1);  
  22.           int i = 0;  
  23.           while(rs.next()){  
  24.             System.out.println("i = "+ i++);  
  25.             rsProc=stmt.executeQuery(sql1)<span style="color:#000000;">;</span>  
  26.             int j =0;  
  27.             while(rsProc.next()){  
  28.                 System.out.println("j = "+ j++);  
  29.             }             
  30.           }  
  31.         }catch(Exception e){  
  32.             System.out.println("数据库连接失败!");  
  33.         }finally{  
  34.             try{  
  35.                 if(rs!=null){  
  36.                     rs.close();  
  37.                 }  
  38.                 if(stmt!=null){  
  39.                     stmt.close();  
  40.                 }  
  41.                 if(conn!=null){  
  42.                     conn.close();  
  43.                 }  
  44.             }catch(Exception e){  
  45.                 System.out.println("数据库连接关闭失败!");  
  46.             }  
  47.         }  
  48.     }  
  49. }  

rs结果集中应该为多条数据,然而rs.next()只能取出集合中的第一条,但是rsProc.next()去记录是正常的。

 

问题解决的方式:
1.新增一个statement对象Statement stmt2=null;
2.将rsProc=stmt.executeQuery(sql1);修改如下:
   stmt2 = conn.createStatement();
   rsProc=stmt2.executeQuery(sql1);

3.在finally中添加如下:
   if(stmt2!=null){
      stmt2.close();
   }
程序运行就正常了。

 

经思考之后,原因如下:
statement用于执行静态 SQL 语句并返回它所生成结果的对象。在默认情况下,同一时间每个 Statement 对象只能打开一个 ResultSet 对象(既同一个Statement打开的ResultSet只有一个记录指针)。因此创建SQL statement在执行sql中的流程,如果读取一个 ResultSet 对象与读取另一个交叉,则这两个对象必须是由不同的 Statement 对象生成的。如果存在某个语句的打开的了前 ResultSet 对象,则Statement 接口中的所有执行方法都会隐式关闭它。这里的ResultSet对象是默认的, ResultSet 对象不可更新,仅有一个向前移动的指针。因此,只能迭代它一次,并且只能按从第一行到最后一行的顺序进行。可以生成可滚动和/或可更新的 ResultSet 对象。以下代码片段(其中 con 为有效的 Connection 对象)演示了如何生成可滚动且不受其他更新影响的、可更新的结果集。

       Statement stmt = con.createStatement(
                                      ResultSet.TYPE_SCROLL_INSENSITIVE,
                                      ResultSet.CONCUR_UPDATABLE);
       ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");

修改前的rsProc=stmt.executeQuery(sql1);中stmt并没有重新创建,因此rsProc对象地址没有发生变化。在rsProc循环取记录的之后,对象中的指示记录的指针已经指向结果集尾部,因而结果集rs再次next()的时候返回的是false,即只取出结果的第一条记录。