Java JDBC結果集的處理


 

結果集指針的移動

while (resultSet.next()){
            //......
}

指針最初指向第一條記錄之前,next()是指向下一個位置,返回的是boolean值,true表示有內容(記錄),false表示無內容(false)。

如果當前是指向最后一條記錄,next()就指向最后一條記錄之后,返回false,退出循環,遍歷完成。

准確地說,應該叫做游標(Cursor),學C++的時候叫指針(Pointer)叫習慣了......

 

//下面3種都是相對當前位置的移動
        resultSet.next();  //指針移到下一個位置
        resultSet.previous();  //指針移到前一個位置

      resultSet.relative(2);  //相對當前位置后移2步
      resultSet.relative(-1);  //正數表示后移,負數表示前移。相對當前位置前移1步。

        //下面5種都是絕對位置的移動
       resultSet.absolute(n); //指向結果集中的第n+1條記錄,n是下標,0表示第一條記錄
resultSet.first(); //指針移到第一條記錄上 resultSet.last(); //指針移到最后一條記錄上 resultSet.beforeFirst(); //指針移到第一條記錄之前 resultSet.afterLast(); //指針移到最后一條記錄之后 //對應的判斷方法 resultSet.isFirst(); resultSet.isLast(); resultSet.isBeforeFirst(); resultSet.isAfterLast();

 

 

 

 

獲取結果集中的記錄總數

1     if(resultSet.last()) {   //指針移到最后一條記錄上,使用if是因為結果集可能是空的,要先判斷
2            System.out.println(resultSet.getRow());  //getRow()是返回當前記錄是結果集中的第幾條記錄,int型
3     }

 

 

 

 

離線查詢

如果要長期使用結果集中的數據,以前有2種方式:

  • 一直保持數據庫連接,不關閉。如果保持的連接很多,服務器、數據庫的性能都會受到影響。
  • 將結果集中的記錄存儲到多個JavaBean中,數據庫沒影響,但要編寫JavaBean,寫代碼遍歷結果集,將每行記錄賦給JavaBean,自己寫代碼的話很麻煩。如果記錄很多,創建大量的JavaBean是很花時間的,JVM要管理大量的JavaBean對象,開銷很大,程序性能降低;且操作結果集比操作JavaBean的集合要簡單。

離線查詢:在本地搞一個結果集的副本,關閉結果集、數據庫連接,使用本地的這個副本。

 

ResultSet接口有子接口RowSet,RowSet有子接口CachedRowSet。離線查詢就是通過CachedRowSet來實現的。

 

 1 //從properties文件中加載數據庫配置
 2         Properties properties = new Properties();
 3         InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
 4         properties.load(inputStream);
 5 
 6         String driver = properties.getProperty("driver");
 7         String url = properties.getProperty("url");
 8         String user = properties.getProperty("user");
 9         String pwd=properties.getProperty("password");
10 
11         Class.forName(driver);
12         Connection connection = DriverManager.getConnection(url, user, pwd);
13 
14         String sql = "select * from student_tb";
15         PreparedStatement preparedStatement = connection.prepareStatement(sql);
16         ResultSet resultSet = preparedStatement.executeQuery();
17 
18         //離線查詢
19         RowSetFactory rowSetFactory = RowSetProvider.newFactory();  //通過RowSetProvider的靜態方法創建RowSetFactory對象
20         CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();  //創建CachedRowSet對象
21         cachedRowSet.populate(resultSet);  //使用結果集填充cachedRowSet
22         //cachedRowSet.populate(resultSet,2);  //可指定從結果集的第幾條記錄開始填充,默認為1,從第一條記錄開始填充
23         
24         //關閉數據庫資源
25         resultSet.close();  
26         preparedStatement.close();  //關閉Statement|PreparedStatement對象
27         connection.close();  
28 
29         //CachedRowSet是ResultSet的孫接口,繼承了ResultSet的屬性、方法,使用方式和ResultSet一樣
30         while(cachedRowSet.next()){
31             int id = cachedRowSet.getInt("id");
32             String name =cachedRowSet.getString("name");
33             int age = cachedRowSet.getInt("age");
34             float score = cachedRowSet.getFloat("score");
35             System.out.println(id+"\t"+name+"\t"+age+"\t"+score);
36         }

 

 

 

 

更新結果集

ResultSet默認是可滾動的、不可更新的,不能刪除、修改結果集中的記錄。如果要獲取可更新的結果集(可增刪改結果集中的記錄),需要在創建Statement | PreparedStatement對象時傳入2個額外的參數。

CachedRowSet默認是可滾動的、可更新的,可刪除、修改CachedRowSet中的記錄。

可滾動指的是可以使用next()、first()、last()、absolute()等方法移動游標,不可滾動指的是只能使用next()來移動游標。

 

可更新的ResultSet:

 1 //從properties文件中加載數據庫配置
 2         Properties properties = new Properties();
 3         InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
 4         properties.load(inputStream);
 5 
 6         String driver = properties.getProperty("driver");
 7         String url = properties.getProperty("url");
 8         String user = properties.getProperty("user");
 9         String pwd=properties.getProperty("password");
10 
11         Class.forName(driver);
12         Connection connection = DriverManager.getConnection(url, user, pwd);
13 
14         String sql = "select * from student_tb";
15         /*
16         獲取可更新的結果集
17 
18         第二個參數指定結果集是否是可滾動的:
19         ResultSet.TYPE_FORWARD_ONLY   不可滾動,只能使用next()移動游標
20         ResultSet.TYPE_SCROLL_SENSITIVE  可滾動,底層數據的變化會同步到結果集(需要底層數據庫驅動的支持)
21         ResultSet.TYPE_SCROLL_INSENSITIVE  可滾動,底層數據的變化不會同步到結果集
22 
23         第三個參數指定結果集是否是可更新的:
24         ResultSet.CONCUR_READ_ONLY   默認值,只讀
25         ResultSet.CONCUR_UPDATABLE   可更新(對結果集中的記錄可增刪改)
26          */
27         PreparedStatement preparedStatement = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
28         ResultSet resultSet = preparedStatement.executeQuery();
29 
30         while (resultSet.next()){
31             int id = resultSet.getInt("id");
32             if(id==5){
33                 //updateXxx()修改當前記錄某個字段的值,第一個參數指定列(字段),可以用列名或列索引,第二個參數指定新值
34                 resultSet.updateString("name","chy");  //修改當前記錄的name字段的值為chy
35                 resultSet.updateRow();  //將對結果集中記錄的改同步到數據庫中,改不會自動同步到數據庫中,需要手動同步
36             }
37             else if(id==10){
38                 resultSet.deleteRow();  //刪除當前記錄(刪除當前行),刪會自動同步到數據庫中
39             }
40         }
41 
42         //往結果集中插入一行
43         resultSet.moveToInsertRow();  
44         /*
45         通過updateXxx()設置插入行的字段值
46 
47         resultSet.updateInt("id",100);
48         如果不設置主鍵列(id)的值,默認插到結果集的末尾,
49         如果結果集中沒有id=100的記錄,但數據庫中有,同步到數據庫時會出錯
50          */
51         resultSet.updateString("name","CoCo");
52         resultSet.updateInt("age",20);
53         resultSet.updateInt("score",90);
54 
55         resultSet.insertRow();  //將增同步到數據庫
56 
57         //這期間需要保持數據庫連接
58         
59         resultSet.close();
60         preparedStatement.close();
61         connection.close();

 

update、insert需要手動同步,delete卻是自動同步,why?

因為delete是一步操作,update、insert均是多步操作,update可能要updateXxx()修改多個字段,insert可能要updateXxx()插入多個字段的值,JVM不知道你的updateXxx()寫完了沒有,所以要寫resultSet.updateRow()|insertRow();   告訴JVM:我對這條記錄的改|插入字段已經弄完了,JVM才會同步到數據庫中。

 

注意是updateRow()、insertRow()、deleteRow(),是Row,不是Rows,同步的只是一條記錄。

所以每操作完一條記錄,該手動同步的就要手動同步,不能想着一次性同步所有更新。

 

 

 

CachedRowSet的更新操作:

 1         //從properties文件中加載數據庫配置
 2         Properties properties = new Properties();
 3         InputStream inputStream =Class.forName("test.Test").getResourceAsStream("/mysql.properties");
 4         properties.load(inputStream);
 5 
 6         String driver = properties.getProperty("driver");
 7         String url = properties.getProperty("url");
 8         String user = properties.getProperty("user");
 9         String pwd=properties.getProperty("password");
10 
11         Class.forName(driver);
12         Connection connection = DriverManager.getConnection(url, user, pwd);
13 
14         String sql = "select * from student_tb";
15         PreparedStatement preparedStatement = connection.prepareStatement(sql);   //CachedRowSet默認就是可更新的,不必傳額外的參數
16         ResultSet resultSet = preparedStatement.executeQuery();
17         resultSet.next();
18 
19         //離線結果集
20         RowSetFactory rowSetFactory = RowSetProvider.newFactory();
21         CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();
22         cachedRowSet.populate(resultSet);
23         resultSet.close();
24         preparedStatement.close();
25         connection.close();
26 
27         while (cachedRowSet.next()){
28             int id = cachedRowSet.getInt("id");
29             if (id==15){
30                 //刪除記錄
31                 cachedRowSet.deleteRow();
32             }
33             else if(id==20){
34                 //修改記錄
35                 cachedRowSet.updateString("name","chy1");
36                 cachedRowSet.updateRow();
37             }
38         }
39 
40         Connection connection1 = DriverManager.getConnection(url, user, pwd);   //連接已關閉了,需要重新獲取一個連接
41         connection1.setAutoCommit(false);  //將新連接的自動提交設置為false
42         cachedRowSet.acceptChanges(connection1);  //同步到數據庫。

 

對CachedRowSet使用deleteRow()、updateRow()不會立刻同步到數據庫中,因為連接已經關閉了,同步不了。

這2個方法相當於把這些同步操作放在一個隊列中,當   cachedRowSet.acceptChanges(connection1);   傳入一個連接時,就依次執行隊列中的同步操作。

 

CachedRowSet不能插入一條記錄,因為CachedRowSet是批量同步的(隊列),插入操作可能會受到隊列中其他記錄的影響。

CachedRowSet是默認可更新的,不是默認自動提交的。

 

更新操作要求結果集滿足2個條件:

  • 結果集只能是單表查詢的結果集
  • 結果集中必須含有主鍵列

 

 

 

 

分頁

分頁有3種實現方式。

1、使用sql語句來限定結果集范圍

1 String sql = "select * from student_tb where id>? and id<?";
2         PreparedStatement preparedStatement = connection.prepareStatement(sql);
3         preparedStatement.setInt(1,0);
4         preparedStatement.setInt(2,11);
5         ResultSet resultSet = preparedStatement.executeQuery();

這種方式不好,因為區間上的某些記錄可能被刪除了,id沒了。比如1頁10條記錄,[1,10],但id=5,id=8的記錄被刪除了(比如注銷賬戶),實際取到的就比10條少。

 

1 String sql = "select * from student_tb limit ?,?";
2         PreparedStatement preparedStatement = connection.prepareStatement(sql);
3         preparedStatement.setInt(1,0);   //從滿足條件的記錄中的第1條記錄起(參數是下標)
4         preparedStatement.setInt(2,10);  //只取10條記錄
5         /*
6         第一個參數可缺省,默認為0,從第一條記錄起。
7         String sql = "select * from student_tb limit 100"; 只取100條記錄
8          */

能取足10條,但limit是mysql的特性,對應的SQL  Server特性是top、Oracle特性是rownum,不跨數據庫。

 

 

2、使用游標來實現

 1  String sql = "select * from student_tb";
 2         PreparedStatement preparedStatement = connection.prepareStatement(sql);
 3         ResultSet resultSet = preparedStatement.executeQuery();
 4 
 5         int start=0;  //開始位置
 6         int pageSize=10;  //每頁顯示多少條記錄
 7         resultSet.absolute(start);  //先轉到起始處。參數是下標,0表示第一條記錄
 8         while (resultSet.next()){
 9             //......
10             System.out.println(resultSet.getRow());
11             if(resultSet.getRow()==start+pageSize)  //getRow()是獲取當前記錄是結果集中的第幾條記錄,第一條就是1。也可以設置計數器來判斷
12                 break;
13         }

 

 

3、使用離線查詢來實現

 1 //離線結果集
 2         RowSetFactory rowSetFactory = RowSetProvider.newFactory();
 3         CachedRowSet cachedRowSet = rowSetFactory.createCachedRowSet();
 4         cachedRowSet.setPageSize(10);  //設置每頁顯示多少條記錄,其實設置的是CachedRowSet的容量
 5         cachedRowSet.populate(resultSet,1);  //設置從結果集中的第幾條記錄開始填充。cachedRowSet中的記錄是結果集中的[1,10]條
 6         resultSet.close();
 7         preparedStatement.close();
 8         connection.close();
 9 
10         while (cachedRowSet.next()){
11            //......
12         }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM