最近在修改多线程批量生成静态报表相关问题时,遇到一个问题,因此回顾一下遗忘的statement对象。
问题描述:
在获取待生成的静态报表时采用连接数据库后创建了Statement对象并调用executeQuery(sql)方法返回ResultSet结果集,然后循环取出相应的记录。山寨测试代码如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
public class ResultSetTest {
public static void main(String[] args) {
String sql1=" select * from LKG_SR_EXCEL_TASK ";
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
ResultSet rsProc=null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
conn=DriverManager.getConnection("jdbc:oracle:thin:@192.168.23.45:1521:ORABI","portal","portal123");
stmt=conn.createStatement();
rs=stmt.executeQuery(sql1);
int i = 0;
while(rs.next()){
System.out.println("i = "+ i++);
rsProc=stmt.executeQuery(sql1)<span style="color:#000000;">;</span>
int j =0;
while(rsProc.next()){
System.out.println("j = "+ j++);
}
}
}catch(Exception e){
System.out.println("数据库连接失败!");
}finally{
try{
if(rs!=null){
rs.close();
}
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}catch(Exception e){
System.out.println("数据库连接关闭失败!");
}
}
}
}
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 对象。因此创建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,即只取出结果的第一条记录。
1、创建 Statement 对象
2、使用 Statement 对象执行语句
3、语句完成
Statement 对象将由 Java 垃圾收集程序自动关闭。而作为一种好的编程风格,应在不需要 Statement 对象时显式地关闭它们。这将立即释放 DBMS 资源,有助于避免潜在的内存问题。
以上若有错误请指正,谢谢!
在编程中寻找快乐,在快乐中自由编程!