簡介
IBM DB2 Driver for JDBC and SQLJ 有一個稱為 useRowsetCursor 的數據源屬性。該屬性的默認值是 true,這意味著在服務器支持的情況下,驅動程序將嘗試對可滾動游標使用多行獲取(MRF)。該屬性允許應用程序在必要時將 MRF 設置為 off。還沒有針對單進游標的 MRF 支持。另外,T2zos (DB2 V9 for z/OS) 尚未支持 MRF。
目前,MRF 支持有 3 個公共接口:
public void setUseRowsetCursor (boolean useRowsetCursor);
public boolean getUseRowsetCursor ();
public boolean getUseRowsetCursor (Java.util.Properties propertIEs);
不過,這不能當成 T2zos 的常規解決方案。這是因為 T2zos 需要行集支持來獲得默認的 false 或 unset。該需求導致需要使用新的屬性覆蓋當前的 useRowsetCursor 屬性(將在下面的 新連接屬性 小節進一步闡述該屬性)。另外,對於 T2zos,新的屬性可用於單進游標和可滾動游標。在 IBM DB2 Driver for JDBC and SQLJ 版本 3.7.xx、3.51.xx、4.1.xx 和更新版本中,都啟用了 MRF for T2zos (DB2 V9 for z/OS) 額外支持。
什麼是多行獲取?
多行獲取允許您從結果表中獲取 0 行或多行。與獲取一個行不同,您可以獲取一組行(稱為行集)。
如 圖 1 所示,通過獲取多個行,應用程序減少了 SQL 調用,並且可以使用一個 FETCH 語句獲取行集。這不僅減少 SQL Application Programming Interface (API) 的交叉使用,還減少了應用程序的該函數的 CPU 使用。
圖 1. 單行獲取和多行獲取比較
新連接屬性
與 MRF 相關的新連接屬性是 enableRowsetSupport。該屬性的可用值包括:
NOT_SET(默認值)
YES
NO
當 enableRowsetSupport 連接屬性設置為 YES 或 NO 時,它將使用 useRowsetCursor 覆蓋當前的設置。
對於 T2zos,如果 enableRowsetSupport 的值為 NOT_SET,這意味著沒有 MRF 支持。對於 T4 和 T2u,NOT_SET 導致使用 useRowsetCursor 屬性的當前值,該屬性的默認值為 true。這意味著如果服務器在 T4 和 T2u 上支持它,將僅對可滾動游標使用 MRF。T4 和 T2u 用戶可以將 useRowsetCursor 設置為 false 或將 enableRowsetSupport 設置為 NO 關閉該行為。
要啟用 MRF,將 enableRowsetSupport 設置為 YES。如果服務器支持,T2zos 將對可滾動游標和單進游標使用 MRF。在未來,T4 和 T2u 可能選擇僅對單進游標使用 MRF。
要禁用 MRF,將 enableRowsetSupport 設置為 NO。這意味著 MRF 對所有類型的用戶禁用(T2zos、T4 和 T2u)。
下面是用於覆蓋 useRowsetCursor 屬性的當前設置的新屬性:
public void setEnableRowsetSupport(int enableRowsetSupport);
public int getEnableRowsetSupport();
public int getEnableRowsetSupport(Java.util.Properties propertIEs);
樣例 Java 程序
清單 1 使用一個樣例 Java 程序,它演示如何使用新的 enableRowsetSupport 連接屬性覆蓋當前的 useRowsetCursor 屬性。
該程序將 enableRowsetSupport 設置為 YES,這意味著將啟用 MRF。
import Java.sql.*;
public class connectionInfo_MRF
{
public static void main(String[] args) throws Exception
{
System.out.println("\nTest case begins !!!\n ");
Javax.sql.DataSource ds = new com.ibm.db2.jcc.DB2SimpleDataSource();
((com.ibm.db2.jcc.DB2BaseDataSource) ds).setServerName("ServerName");
((com.ibm.db2.jcc.DB2BaseDataSource) ds).setPortNumber(portNumber);
((com.ibm.db2.jcc.DB2BaseDataSource) ds).setDatabaseName("databaseName");
((com.ibm.db2.jcc.DB2BaseDataSource) ds).setDriverType(2);
// Enable MRF support. To disable MRF, set setEnableRowsetSupport
// to com.ibm.db2.jcc.DB2BaseDataSource.YES
int setValue = com.ibm.db2.jcc.DB2BaseDataSource.YES;
((com.ibm.db2.jcc.DB2BaseDataSource)ds).setEnableRowsetSupport(setValue);
((com.ibm.db2.jcc.DB2BaseDataSource) ds).setTraceFile("jccTrace.txt");
System.out.println(((com.ibm.db2.jcc.DB2BaseDataSource) ds).getJccVersion());
Java.sql.Connection con = ds.getConnection("userName", "passWord");
// Get Rowset support value. When MRF is enabled this should return value 1.
int RowSet = ((com.ibm.db2.jcc.DB2BaseDataSource)ds).getEnableRowsetSupport();
System.out.println("\nRow Set Support value :" +RowSet);
System.out.println("\n");
// Set the cursor type to scrollable.
//Modify the below statement if you want the cursor type to be TYPE_FORWARD_ONLY
Java.sql.Statement s = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
// Create table
s.executeUpdate ("create table TestQBatch (col1 int)");
// Populate tables with data.
for (int i =1; i less than 1000; i++)
{
s.executeUpdate ("insert into TestQBatch values (" +i+ ")");
}
Java.sql.ResultSet rs = s.executeQuery("Select * from TestQBatch");
while (rs.next())
{
System.out.print (rs.getInt (1) + " ");
}
// When MRF is enabled, ResultSet.getFetchSize() should alway return value > 1.
int ActualResult = rs.getFetchSize();
System.out.print ("\n\nFetch Size : " +ActualResult);
// Drop the table created.
s.executeUpdate("DROP TABLE TestQBatch");
System.out.println("\n\nTest case Ends !!! ");
con.commit();
}
}
如何確定是否對獲取使用 MRF
在包含 IBM DB2 Driver for JDBC and SQLJ 版本 3.7.xx、3.51.xx、4.1.xx 或更新版本的 T2zos (DB2 V9 for z/OS) 機器上運行 清單 1 中的樣例程序。找到名為 jccTrace.txt 的 JCC 跟蹤文件。如前所述,在支持 MRF 的 T2zos 服務器上,如果 enableRowsetSupport 設置為 YES,T2zos 為游標准備 WITH ROWSET POSITIONING。
如果 jccTrace.txt 跟蹤文件包含字符串 WITH ROWSET POSITIONING,這意味著啟用了 MRF。如果沒有啟用 MRF,准備 FETCH 語句時將不包含行集定位。所以在這個例子中,您不能在跟蹤文件中找到字符串 WITH ROWSET POSITIONING。
您還可以通過調用 ResultSet.getFetchSize() 確定特定 ResultSet 的 MRF 是否處於活動狀態。如果 fetchSize 的返回值大於 1,那麼就使用了 MRF。注意,這是 ResultSet 而不是 PreparedStatement 上的調用。
限制
由於受到 DB2 的限制,行集游標(MRF)與 T2zos (Fetch Continue) 中的漸進式流不兼容。
在 T2zos 中,如果您將 enableRowsetSupport 設置為 YES,並且服務器支持 MRF,那麼 T2zos 將為游標准備 WITH ROWSET POSITIONING。不過,如果在游標中出現大對象或 XML,並且漸進式流使用默認值或設置為 on,將對 FETCH 語句關閉 MRF(OFF )。將重新准備 FETCH 語句,並且不包含行集定位。
T2zos 不知道從存儲過程返回的游標是不是一個行集,因此 t2zos 驅動程序僅允許對存儲過程執行單行獲取。
T2zos 不支持從存儲過程返回的並且是漸進式流形式的大對象或 XML。在獲取繼續 (T2zosCursor.getMoreData_) 調用期間,該情況可能導致拋出 -225 sqlcode。
如果游標中出現大對象或 XML,T2zos Java 存儲過程將關閉行集支持。
結束語
使用多行獲取 (MRF),您可以獲得比使用 FETCH 語句每次獲取一行更佳的性能。本文幫助您理解了 MRF 及其使用方式。此外,還通過一個簡單的樣例 Java 程序演示如何在 Java 程序中設置 MRF,並解釋如何確定是否使用了 MRF。
多行定位 UPDATE 或 DELETE
IBM Data Server Driver for JDBC and SQLJ 支持執行遵循 JDBC 1 標准的定位 UPDATE 或 DELETE 操作。對於行集游標,JDBC 1 定位更新語法必須知道行集的存在。該語法必須遵循以下格式:
update table set.... where current of cursor for row N of rowset
如果應用程序想要使用 JDBC 1 定位 UPDATE 操作,那麼它必須構建正確定位的 UPDATE/DELETE 語句。
不過,當前的 t2zos 應用程序仍然使用 JDBC 1 定位 UPDATE 語句,其遵循的格式如下:
update table set....where current of cursor
因此,行集支持導致不同的行為。UPDATE 影響整個行集,而不是單個行。因此,t2zos 行集支持的默認設置為 false(見 新連接屬性 小節)。
該技術涉及到使用 ResultSet.getCursorName 方法為 ResultSet 獲取游標的名稱,以及按照以下格式定義定位 UPDATE 或定位 DELETE 語句:
UPDATE table SET col1=value1…coln=valueN WHERE CURRENT OF cursorname
DELETE FROM table WHERE CURRENT OF cursorname
如果您使用 JDBC 1 技術對支持多行獲取的數據源中的數據執行 UPDATE 或 DELETE 操作,定位 UPDATE 或 DELETE 語句可能 UPDATE 或 DELETE 多個行,盡管您可能希望它僅 UPDATE 或 DELETE 單個行。
要避免意外的 UPDATE 或 DELETE 操作,您可以采取以下措施之一:
使用可更新的 ResultSet 一次僅獲取和 UPDATE 一個行。
在 UPDATE 或 DELETE 語句中使用 FOR ROW n OF ROWSET 子句, 以識別需要執行 MODIFY 或 DELETE 操作的特定行。