JDBC3.0的特性
1、JDBC3.0規范中數據庫連接池框架
JDBC3.0規范中通過提供了一個支持數據庫連接池的框架,這個框架僅僅規定了如何支持連接池的實現,而連接池的具體實現JDBC 3.0規范并沒有做相關的規定。通過這個框架可以讓不同角色的開發人員共同實現數據庫連接池。
通過JDBC3.0規范可以知道具體數據庫連接池的實現可以分為JDBC Driver級和Application Server級。在JDBC Driver級的實現中任何相關的工作均由特定數據庫廠商的JDBC Drvier的開發人員來具體實現,即JDBC Driver既需要提供對數據庫連接池的支持同時也必須對數據庫連接池進行具體實現。而在Application Server級中數據庫連接池的實現中特定數據庫廠商的JDBC Driver開發人員和Application Server開發人員來共同實現數據庫連接池的實現(但是現在大多數Application Server廠商實現的連接池的機制和規范中提到有差異),其中特定數據庫廠商的JDBC Driver提供數據庫連接池的支持而特定的Application Server廠商提供數據庫連接池的具體實現。
JDBC3.0規范規定了如下的類和接口來支持數據庫連接池的實現。
javax.sql.ConnectionEvent javax.sql.ConnectionPoolDataSource javax.sql.PooledConnection javax.sql.ConnectionEventListener
其中除javax.sql.ConnectionEvent是類,其它的均為接口。
JDBC3.0連接池框架的關系圖
通過此圖可以大概的了解相關接口在一個典型的三層環境中應用程序的位置。
2、檢索自動產生的關鍵字
為了解決對獲取自動產生的或自動增加的關鍵字的值的需求,JDBC 3.0 API 現在將獲取這種值變得很輕松。要確定任何所產生的關鍵字的值,只要簡單地在語句的 execute() 方法中指定一個可選的標記,表示您有興趣獲取產生的值。您感興趣的程度可以是 Statement.RETURN_GENERATED_KEYS,也可以是 Statement.NO_GENERATED_KEYS。在執行這條語句后,所產生的關鍵字的值就會通過從 Statement 的實例方法 getGeneratedKeys() 來檢索 ResultSet 而獲得,ResultSet 包含了每個所產生的關鍵字的列,下面的示例創建一個新的作者并返回對應的自動產生的關鍵字。
…… Statement stmt = conn.createStatement(); // Obtain the generated key that results from the query. stmt.executeUpdate("INSERT INTO authors " + "(first_name, last_name) " + "VALUES (‘Ghq’, ‘Wxl’)", Statement.RETURN_GENERATED_KEYS); ResultSet rs = stmt.getGeneratedKeys(); if ( rs.next() ) { // Retrieve the auto generated key(s). int key = rs.getInt(); } ……
3、返回多重結果
JDBC 2 規范的一個局限是,在任意時刻,返回多重結果的語句只能打開一個ResultSet。作為 JDBC 3.0 規范中改變的一個部分,規范將允許 Statement 接口支持多重打開的 ResultSets。然而,重要的是 execute() 方法仍然會關閉任何以前 execute() 調用中打開的 ResultSet。所以,要支持多重打開的結果,Statement 接口就要加上一個重載的 getMoreResults() 方法。新式的方法會做一個整數標記,在 getResultSet() 方法被調用時指定前一次打開的 ResultSet 的行為。接口將按如下所示定義標記:
CLOSE_ALL_RESULTS:當調用 getMoreResults() 時,所有以前打開的 ResultSet 對象都將被關閉。
CLOSE_CURRENT_RESULT:當調用 getMoreResults() 時,當前的 ResultSet 對象將被關閉。
KEEP_CURRENT_RESULT:當調用 getMoreResults() 時,當前的 ResultSet 對象將不會被關閉。
下面展示的是一個處理多重打開結果的示例。
…… String procCall; // Set the value of procCall to call a stored procedure. // … CallableStatement cstmt = connection.prepareCall(procCall); int retval = cstmt.execute(); if (retval == false) { // The statement returned an update count, so handle it. // … } else { // ResultSet ResultSet rs1 = cstmt.getResultSet(); // … retval = cstmt.getMoreResults(Statement.KEEP_CURRENT_RESULT); if (retval == true) { ResultSet rs2 = cstmt.getResultSet(); // Both ResultSets are open and ready for use. rs2.next(); rs1.next(); // … } } ……4、在事務中使用 Savepoint
也許在 JDBC 3.0 中最令人興奮的附加特點就是 Savepoint 了。JDBC 2 中的事務支持讓開發人員可以控制對數據的并發訪問,從而保證持續數據總是保持一致的狀態。可惜的是,有時候需要的是對事務多一點的控制,而不是在當前的事務中簡單地對每一個改變進行回滾。在JDBC 3.0 下,可以通過 Savepoint 獲得這種控制。Savepoint 接口允許您將事務分割為各個邏輯斷點,以控制有多少事務需要回滾。下圖將說明如何在事務中運用 Savepoint。
Savepoint 的直觀表示
你或許不是經常需要使用 Savepoint。然而,在一種普遍的情況下 Savepoint 會發揮作用,那就是您需要作一系列的改變,但是在知道所有的結果之前不能確定應該保留這些改變的哪一部分。下面的代碼示例說明了如何使用 Savepoint 接口。
......
conn.setAutoCommit(false);
// Set a conservative transaction isolation level.
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate( "INSERT INTO authors " +
" (first_name, last_name) VALUES " +
" ('Ghq', 'Wxl')");
// Set a named savepoint.
Savepoint svpt = conn.setSavepoint("NewAuthor");
// …
rows = stmt.executeUpdate( "UPDATE authors set type = 'fiction' " +
"WHERE last_name = 'Wxl'");
// …
conn.rollback(svpt);
// …
// The author has been added, but not updated.
conn.commit();
......
5、其他的特性
1)元數據 API
元數據 API 已經得到更新,DatabaseMetaData 接口現在可以檢索 SQL 類型的層次結構,一種新的 ParameterMetaData 接口可以描述 PreparedStatement 對象中參數的類型和屬性。
2)CallableStatements 中已命名的參數
在 JDBC 3.0 之前,設置一個存儲過程中的一個參數要指定它的索引值,而不是它的名稱。 CallableStatement 接口已經被更新了,現在您可以用名稱來指定參數。
3)數據類型的改變
JDBC 所支持的數據類型作了幾個改變,其中之一是增加了兩種新的數據類型。
為了便于修改 CLOB(Character Large OBject,字符型巨對象)、BLOB(Binary Large OBject,二進制巨對象)和 REF(SQL 結構)類型的值,同名的數據類型接口都被更新了。接下來的是,因為我們現在能夠更新這些數據類型的值,所以 ResultSet 接口也被修改了,以支持對這些數據類型的列的更新,也包括對 ARRAY 類型的更新。增加的兩種新的數據類型是 java.sql.Types.DATALINK 和 java.sql.Types.BOOLEAN。新增的數據類型指的是同名的 SQL 類型。DATALINK 提供對外部資源的訪問或 URL,而 BOOLEAN 類型在邏輯上和 BIT 類型是等同的,只是增加了在語義上的含義。DATALINK 列值是通過使用新的 getURL() 方法從 ResultSet 的一個實例中檢索到的,而 BOOLEAN 類型是通過使用 getBoolean() 來檢索的。
二進制大對象Blob
Blob對象是SQL Blob的Java語言映射。SQL Blob是一個內置類型,它可以將一個二進制大對象保存在數據庫中。接口ResultSet、CallableStatement和PreparedStatement中的方法允許程序員使用與訪問SQL 92內置類型同樣的方式來訪問SQL 99類型BLOB。
在標準實現中,JDBC驅動程序在后臺使用SQL類型LOCATOR(BLOB)來實現Blob接口。LOCATOR(BLOB)指向保存在數據庫服務器上的SQL BLOB值,而且這些操作作用在這個LOCATOR(定位器)上與作用在BLOB值本身有同樣的結果。這意味著用戶可以在一個Blob實例上執行操作而不必將這個BLOB數據物化到用戶上,這將顯著的提高性能。因為驅動程序在后臺使用LOCATOR(BLOB),所以它的使用對程序員是完全透明的。
Blob實例的標準行為一直保持有效,直到這個事務(創建一個Blob的事務)執行了提交或者回滾操作。
-
創建Blob對象
下面的代碼說明了如何創建一個Blob對象,其中stmt是一個Statement對象:
Statement stmt = con..createStatement(ResultSet.TYPE_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stmt.excuteQuery(“SELECT DATA FROM TABLE 1”);
If (rs.next()){
rs.first();
Blob blob=rs.getBlob(“DATA”);
}
變量blob包含一個指向BLOB值的邏輯指針,該BLOB值保存在結果集rs的第一行的DATA列中。即使變量blob實際上并不包含BLOB值中的數值,應用程序在blob上執行操作仍然像在實際的數據上執行一樣。即應用程序在blob上所作的任何操作都會對表中的BLOB值起作用。
-
物化BLOB數據
開發人員可以在Blob對象上調用JDBC API中的方法,就像這些方法直接
在該對象所指向的SQL BLOB上執行操作一樣。然而,如果想在BLOB數據上執行操作,就必須首先將BLOB數據物化到客戶。Blob接口提供了兩個方法來物化BLOB數據:getBinaryStream,這個方法將BLOB數據物化為一個輸入流;getBytes,這個方法將BLOB值得一部分或者全部物化為一個字節數組。下面的代碼說明了如何將Blob所指向的BLOB值得全部物化為一個輸入流:java.io.InputStream in = blob.getBinaryStream(); byte b; while((b = in.read()) >-1){ System.out.println(b); }
接下來的代碼同樣物化了blob所指向的BLOB值得所有數據,但是它產生的是字節數組而不是輸入流。long len = blob.length(); byte [] data = blob.getBytes(1,len); for(int i=0;i<len;i++){ byte b = data[i]; System.out.println(b); }
變量data復制了blob所指向的BLOB值的所有字節。這是因為傳遞給方法getBytes的參數值說明了整個BLOB值:第一個參數表示從第一個字節開始返回字節,第二個參數說明它返回的字節長度是BLOB值的長度。
需要說明的是,因為SQL和Java語言之間的不同,一個BLOB值得第一個字節在位置1,而Java數組的第一個元素的索引是0。 -
存儲Blob值
若要在數據庫中存儲Blob值,應用程序可以把它作為一個參數傳遞給
PreparedStatement的方法setBlob。下面的代碼就實現了這個功能:PreparedStatement的方法setBlob。下面的代碼就實現了這個功能: Blob stats = rs.getBlob(“STATS”); PreparedStatement pstmt= con.preparedStatement( “UPDATE SIGHTINGS SET MEAS= ? WHERE AREA = ‘BEIJING’ ”); pstmt.setBlob(1,stats); pstmt.excuteUpdate();
-
發現Blob對象中的模式
如果一個Blob對象包含一個給定的字節集合,應用程序可以使用方法
position的兩個方法來找到它。其中一個方法搜索一個給定的字節數組,而另一個在一個Blob對象中搜索一個給定的Blob對象。如果發現一個匹配的結果,則返回該模式字節的起始位置。 -
修改Blob對象的方法
JDBC 3.0 API中新增的方法setBytes和setBinaryStream允許應用程序對
Blob對象進行修改。
方法setBytes有兩個方法來向Blob對象添加數據。其中一個方法增加給定的字節數組的全部內容,而另一個方法增加給定字節數組的特定部分。兩個方法都使用一個參數說明向Blob對象插入數據的起始位置。例如,下面的代碼段在一個Blob對象blob1的第一個字節處寫入整個字節數組bytes。在這種情況下,bytes包含了Blob對象blob的所有字節,因此執行的結果是blob2被寫入了blob1的起始處。需要注意的是如果blob2的長度是1024字節,那么blob2的1024各字節將覆蓋blob1的開頭的1024各字節。byte [] bytes = blob2.getBytes(1,blob2.length()); blob.setBytes(1,bytes,0,512);
下面的代碼段說明如何僅僅向Blob對象加入一個字節數組的特定部分。在這種情況下,方法setBytes接受兩個附加的參數來說明需要增加字節數組的哪一個部分。其中一個參數指明了這個字節數組的起始偏移量,另一個參數說明這個字節數組包含多少個連續的字節。byte [] bytes={……}; blob.setBytes(1,bytes,0,512);
除了可以向Blob對象增加字節之外,Blob接口還提供了刪除字節的方法。方法truncate接受一個字節數目作為一個參數并且根據這個數目來縮短Blob對象。 -
定位器和更新
在標準實現中,指向SQL BLOB的Blob對象使用了SQL LOCATOR類型。定位器(locator)是一個指向保存在數據庫中的BLOB值的指針,而DBMS如何更新一個作為定位器實現的對象則依賴于具體的數據庫。某些DBMS會更新表中的BLOB值,而另一些則僅僅更新BLOB值的一個副本,并不改變數據庫中的值。在后一種情況下,應用程序必須直接更新BLOb值。
為了發現DBMS是如何更新BLOB值的,應用程序可以調用DatabaseMetaData的方法locatorsUpdateCopy。如果這個方法返回true,則應用程序必須自己更新數據庫中的BLOB值。下面的代碼顯示了這個過程:首先從rs取回Blob對象,然后把它的值改為字節數據val的值。如果方法locatorsUpdateCopy返回true,那么它隨后執行一個PreparedStatement對象來更新數據庫中的值。如果方法locatorsUpdateCopy返回false,代碼什么也不用做,因為數據庫中的值已經被更新過了。byte [] val ={0,1,2,3,4}; Blob data =rs.getBlob(“DATA”); int numWritten = data.setBytes(1,val); if (dbmd.locatorUpdateCopy() == true){ PreparedStatement pstmt= con . preparedStatement( “UPDATE statistics SET DATA = ? WHERE REGION = ‘BEIJING’ “); pstmt.setBlob(“DATA”,data); pstmt.executeUpdate(); }
字符大對象Clob
-
創建Blob對象
Clob clob = rs.getClob(1);
變量clob現在可以被用于在CLOB值上執行操作,而假設這CLOB值保存在結果集rs的第一列中。 -
物化Clob數據
和物化Blob的方式一樣。不過Clob接口提供了三種方法達到將CLOB作為一個Java對象的形式保存在客戶的內存中。使用getAsiiStream把CLOB值物化為一個包含Ascii字節的字符流。 ① 使用getAsiiStream把CLOB值物化為一個包含Ascii字節的字符流。 Clob notes = rs.getClob(“NOTES”); java.io.InputStream in = notes.getAsciiStream(); byte b = in.read(); ② 使用getCharacterStream把CLOB值物化為一個Unicode字符流。 Clob notes = rs.getClob(“NOTES”); java.io.Reader reader = notes.getCharacterStream(); int c = reader.read(); // ③ 使用getSubString將CLOB值的全部或者部分化為一個String對象。 Clob notes = rs.getClob(4); String substring= notes.getSubString(10,5); 或者 long len =notes.length(); String substring = notes.getSubString(1,(int)len);
-
存儲、更新Clob對象
和存儲、更新Blob對象類似。
元數據接口使用詳解
三個元數據接口DatabaseMetaData、ResultSetMetaData和ParameterMetaData接口是三個常用的元數據接口。DatabaseMetaData提供與數據庫或者DBMS相關的信息;ResultSetMetaData對象提供與特定ResultSet實例中與列相關的信息;ParameterMetaData對象提供與PreparedStatement對象的參數有關的信息。本文討論的內容并不僅限于JDBC的某個版本,而是基于1.0—3.0的規范進行學習。
-
ResultSetMetaData對象
當在JDBC應用程序中發送select語句時,該操作會返回一個ResultSet對象,這個ResultSet對象包含滿足條件的數據。通過創建ResultMetaData對象和調用該對象的方法,可以獲取與這個ResultSet對象中的列有關的信息。下面的代碼段將創建ResultSet對象rs,然后使用rs來創建ResultSetMetaData對象,所創建的ResultSetMetaData對象包含與rs中的列有關的信息。Statement stmt= con . createStatement(); ResultSet rs = stmt.executeQuery(“select * from sales”); ResultSetMetaData rsmd = rs.getMetaData();
現在可以使用rsmd調用ResultSetMetaData的方法來訪問與rs中的列有關的信息。除了方法getColumnCount給出結果集中總的列數外,所有的ResultSetMetaData方法都返回與單個列有關的信息,并都接受一個表示對應列號的參數。-
getColumnCount方法
這也許是ResultSetMetaData中使用最多的方法,該方法返回結果集中列數目 :ResultSet rs = stmt.executeQuery(“select * from sales”); ResultSetMetaData rsmd = rs.getMetaData(); int numberOfColumns = rsmd.getColumnCount(); while(rs.next()){ for(int i=1;i<=numberOfColumn;i++){ String s = rs.getString(i); System.out.println(“Column ” +i +”: ” +s +” ”); } }
需要注意的是,用于檢索所有列值的ResultSet方法是getString。當不知道每一列的類型,這是比較容易的方法;如果希望能檢索所有的數據類型(包括SQL 99數據型),則可以使用方法getObject,這是保證能夠檢索所有列值得唯一方法。 -
獲取列類型信息
有兩個ResultSetMetaData方法可以獲取與結果集列的類型有關的信息。這 兩個方法是getColumnType和getColumnTypeName。getColumnType方法用于確定存儲在指定列中的值的JDBC類型。該方法以一個int值來返回JDBC類型。如下面的代碼獲得rs第二列的JDBC類型:ResultSetMetaData rsmd = rs.getMetaData(); int jdbcType = rsmd.getColumnType(2);
-
獲取其他信息
另外有幾個方法用來提供與存儲數值類型的列有關的信息。isAutoIncrement isCurrency isSigned getPrecision getScale isNullable getColumnDisplaySize
-
使用DatabaseMetaData對象
接口DatabaseMetaData提供了大量的方法取得與數據庫相關的信息。一旦獲得了打開的連接,就可以創建包含與數據庫系統有關的信息的DatabaseMetaData對象。 -
DatabaseMetaData方法的類別
按照返回值的類型對DatabaseMetaData的方法進行分類,可以分為4種。
有三種類型返回單一的值,另外一種返回一個結果集,這個結果集包含1~18列的數據。 ① 返回String的方法
最小的類別是指返回String對象的DatabaseMetaData方法。這些方法中的一些方法可以獲取與DBMS有關的總體信息,包括數據庫的URL、username、產品名稱、驅動程序信息等等。
② 返回int的方法
③ 返回boolean的方法
④返回ResultSet對象的方法
這些方法可以返回ResultSet對象,所返回的ResultSet對象可以包含1到最多18列。 -
獲取與主外鍵有關的信息
返回與主外鍵有關信息的方法主要有getPrimaryKeys、getImportedKeys、getExportedKeys以及getCrossReference等。
下面的代碼段顯示了如果在定義表時指定了主鍵,則可以調用方法getPrimaryKeys開獲取對于表中主鍵列的描述。import java.sql.*; public class static PrimaryKeysExample{ public static void main(String args[]){ String url =”jdbc:mySubprotocol:myDataSource”; Connection con; String createString =”create table supplierspk”+ “(sup_id integer not null,”+ “sup_name varchar(40),”+ “street varchar(40),”+ “city varchar(20)”+ “state char(10),”+ “zip char(10),”+ “primary key(sup_id))”; Statement stmt; try{ Class.forName(“myDriver.className”); }catch(java.lang.ClassNotFoundException e){ System.err.println(“ClassNotFoundException: ”); System.err.println(“e.getMessage()”); } try{ con =DriverManager.getConnection(url,”username”,”pwd”); stmt=con.createStatement; stmt.executeUpdate(createString); DatabaseMetaData dbmd=con.getMetaData(); ResultSet rs= dbmd.getPrimaryKey(null,null,”suplierspk”); While(rs.next()){ String name =rs.getString(“table_name”); String columnName=rs.getString(“column_name”); String keySeq=rs.getString(“key_seq”); String pkName=rs.getString(“pk_name”); System.out.println(“table name :”+name); System.out.println(“column name: ”+columnName); System.out.println(“sequence in key:”+keySeq); System.out.println(“primary key name:”+pkName); } rs.close(); stmt.close(); con.close(); }catch(SQLException ex){ System.err.println(“SQLException: ”+ex.getMessage()); } } }
如果主鍵多余一列的話,那么方法getPrimaryKeys等將詳細描述每一列。列key_seq中的值表示描述的是哪一列。
-
getColumnCount方法
-
使用ParameterMetaData對象
可以使用ParameterMetaData對象來獲取與PreparedStatement對象或者CallableStatement對象有關的信息。這些參數由”?”占位符表示,”?”占位符是提供給Connection方法prepareStatement和prepareCall的SQL語句。下面的代碼行使用兩個參數占位符來創建一個PreparedStatement對象。
PreparedStatement pstmt=con.prepareStatement(“select id from employees where dept=? and salary>?”);
這些參數根據其序號來編號,因此第一個參數編號1,第二個參數編號2,依此類推。在上面的代碼行中,參數1是列dept中的一個值,參數2是salary中的一個值。下面的代碼段用于找出PreparedStatement pstmt有多少個參數。首先創建pstmt并用它來創建ParameterMetaData對象pmd,這個對象包含與pstmt中的參數有關的信息。接著調用pmd上的方法getColumnCount來找出pstmt有多少參數。PreparedStatement pstmt=con.prepareStatement( “update employees set salary =? Where level=?”); ParameterMetaData pmd = pstmt.getParameterMetaData(); int count=pmd.getParameterCount();
變量count的值應該等于2。方法getParameterCount不接受參數,因為它返回與PreparedStatement對象的所有參數有關的信息。ParameterMetaData接口中的所有其他方法都接受序號來表示作為要查詢的信息的參數。
-
JDBC 3.0API中新增的方法示例
JDBC 3.0 API引入了這樣一種應用功能,即決定在已經調用commit方法來終止事務之后,ResultSet對象是否仍舊打開。這個功能即為結果集可保持性。ResultSet中加入了兩個域HOLD_CURSORS_OVER_COMMIT和 CLOSE_CURSORS_AT_COMMIT,這些域可以用于指定ResultSet對象的可保持性,這些常量可以提供給創建Statement、PreparedStatement和CallableStatement對象的Connection方法,還可以作為提供給DataBaseMetaData方法supportResultSetHoldability的可能的參數值。
在下面的代碼段中,首先判斷驅動程序是否支持ResultSet可保持性,如果支持,則接著創建會生成帶有可保持性游標的ResultSet對象的Statement對象,另外此代碼還指定了stmt在執行查詢時產生的ResultSet對象的類型和并發模式。
if (Boolean b =dbms.supportsResultSetHoldability(
ResultSet. HOLD_CURSORS_OVER_COMMIT){
Statement.stmt=con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
RowSet
RowSet對象是表格式數據的容器,封裝了一組從數據源獲取得數據行。在RowSet接口的基本實現中是從JDBC數據源中獲取數據行。由于行集是可以定制的,所以行集中的數據可以來自電子數據表、flat文件(平面文件?)或者其他任何表格式樣的數據源。RowSet對象是ResultSet接口的擴展,這就意味著RowSet對象是可滾動的、可更新的,并且能夠執行ResultSet對象可以執行的任何操作。
RowSet對象不同于ResultSet對象,它是JavaBean組件,因此,該對象有JavaBean屬性,并遵循其事件模型。另外RowSet對象的屬性也允許該對象建立自己的數據庫連接,執行自己的查詢。此外,RowSet可以是disconnected的,也就是說使用行集的過程中,不必一直保持到數據源的打開連接。另外,行集可以串行化,所以可以通過網絡把它發送到遠程對象中去。
通常情況下,JDBC API可以分為兩類:RowSet部分和驅動程序部分。RowSet以及支持它的接口使用其他JDBC API實現。從邏輯上來說,可以把實現RowSet接口的類看作是執行在JDBC驅動程序的上一層的軟件。
現在的J2SE 5.0中,可以把JDBC API分為三種類別,除了上面的兩類,還有RowSet接口的5種標準實現。這些實現提供了一組接口,以擴展基本的RowSet接口,通過在這些接口上建立application,可以確保在事件處理、游標控制以及其他操作方面的實現遵循JDBC API。
RowSet接口提供了一組基本方法,這些方法對于所有行集都是通用的。因為所有的RowSet對象都是JavaBean組件,因此,RowSet接口具有添加和刪除event listener的方法,也有get/set RowSet對象所有屬性的方法。RowSet對象的大多數屬性都支持建立連接或者執行命令。為了執行查詢、更新等SQL語句,并生成能夠從中獲取數據的結果集,行集會使用到數據源的連接。
若一個組件希望得到在RowSet對象上發生的事件的通知,它就應該實現RowSetListener接口,并向RowSet對象進行注冊。這就是listener,一個GUI組件。這樣每當行集產生事件時,listener每次都會得到事件的通知,這樣就能夠保持它的游標位置和數據與行集的內容一致。
RowSetInternal、RowSetReader、和RowSetWriter接口支持行集的reader/weiter工具。reader是一個實現RowSetReader接口的類的實例,用來讀取數據并數據插入到行集中。writer是一個實現RowSetWriter接口的類的實例,用來將修改后的數據寫回到數據源。reader和writer就像是listener一樣,都向行集進行動態注冊。
調用reader或者writer的RowSet對象必須是實現RowSetInternal接口的類的實例。這個接口為reader或者writer提供了附加的方法,用來操作行集的內部狀態。例如行集可以跟蹤它的初始值,RowSetInternal方法允許writer檢測數據源中的相應數據是否已經被其他用戶修改。另外,能夠使用RowSetInternal方法來獲取為行集的命令字符串設置的輸入參數,也能夠獲取傳遞給行集的連接。最后,RowSetInternal方法允許reader設置新的RowSetMetaData對象,這個對象用來為行集描述reder將要插入到該行集中的數據行。
行集可以是connected的,也可以是disconnected的,一個連接的RowSet對象,在使用的整個過程中保持到數據源的連接,而一個未連接的行集,只有從數據源讀取數據或者將數據寫回數據源時才會連接到它的數據源。若行集是未連接的,它就不需要JDBC驅動或者JDBC API的完整實現。這使得它非常小巧,因此也成為發送一組數據到一個thin client的理想的容器。這個客戶端可以選擇更新數據,并將行集發送回應用服務器。在服務器端,未連接的RowSet對象使用它的reader來建立到數據源的連接,并把數據寫回數據源。這一操作的具體實現依賴于reader的實現方式。通常reader將建立連接與讀/寫數據的操作委托給JDBC驅動。
行集的事件模型
行集事件模型使得Java對象或者組件能夠收到RowSet對象產生的事件的通知。通知機制的建立包括被通知的組件,也包括RowSet對象自身。首先,每一個希望得到事件通知的組件都必須實現RowSetListener接口。然后,RowSet對象必須注冊每一個組件,這通過在RowSet對象的事件通知組件列表中添加這些組件來完成。在這種情況下,這樣的組件是一個listener,它是一個實現RowSetListener方法的類的實例,并已經向RowSet對象進行過注冊。
在RowSet對象中可能發生三種事件:游標移動、數據行發生變化(ins、del、upd)或者該對象的整個內容發生變化。RowSetListener接口的cursorMoved、rowChanged和rowSetChanged方法分別對應與這些事件。當事件發生時,行集將創建一個RowSetEvent對象,使用這個對象將該行集標識為事件源。在每一個listener上調用適當的RowSetListender方法,并向此方法傳遞一個RowSetEvent對象作為輸入參數,就將事件通知給行集所有的listener。
RowSet屬性
RowSet接口提供了一組JavaBeans屬性,可以配置RowSet實例以連接到數據源并獲取數據行集合。有些屬性可能并不需要,這取決于特定實現。如用URL或者數據源名來建立連接,但只要設置了其中一個屬性,另一個屬性就是可選的。如果設置了兩個屬性,就會使用最近設置的那個屬性。若行集的數據是從不支持名命令的非SQL數據源中如電子表格中獲取的,那么就不需要設置命令屬性。
幾個接口的講解
-
WebRowSet
WebRowSet接口擴展了CacheRowSet接口。相比CacheRowSet接口,增加了讀寫XML格式行集的能力。WebRowSetImpl對象使用WebRowSetXmlReader對象來讀取XML格式的行集,使用WebRowSetXmlWriter對象向XML格式的行集中寫入數據。XML版本包含WebRowSetSetImpl對象的元數據,同時也包含它自己的數據。 WebRowSetImpl對象和CachedRowSetImpl相似點是二者都將瘦客戶端連接到應用服務器。所以它們都適合為瘦客戶提供數據;不同的地方是二者使用的協議。前者使用http/xml協議與中間層進行通信,而后者使用RMI/IIOP。
-
JoinRowSet
JoinRowSet對象使得程序員能夠從兩個不同的RowSet對象合并數據。當相關聯(p/f keys相關或者其他列唯一對應)的數據存儲在不同的數據源中時,這種合并數據的功能很有用。任何RowSet實現都可以參與合并,但通常情況下,連接的雙方是兩個CachedRowSetImpl對象。將相關數據合并到一個JoinRowSetImpl對象中,應用程序就能夠處理任何其他類型的RowSet對象一樣來處理這些數據。
假設有兩個表:employees表和bonus_plan表,兩表的第一個數據列都是ID,這個數據列是主鍵,現要將兩表的信息進行匹配合并:JoinRowSetImpl jrs=new JoinRowSetImpl(); ResultSet rs1 = stmt.executeQuery(“select * from employees”); CachedRowSetImpl empl=new CachedRowSetImpl(); empl.populate(rs1); empl.setMatchColumn(1); jrs.addRowSet(empl); ResultSet rs2=stmt.executeQuery(“select * from bonum_plan”); CachedRowSetImpl bonums= new CachedRowSetImpl(); bonus.populate(rs2); bonus.setMatchColumn(1); jrs.addRowSet(bonus);//已合并
XAConnection 介紹
XAConnection對象是可以用于分布式事務的PooledConnection對象。它表示數據庫的物理連接,多層結構中的服務器可以用它來創建返回給應用程序的Connection對象。因為是通過擴展PooledConnection接口得到的,所以繼承了其所有的方法,另外添加了自己的方法 getXAResource。
分布式事務中的命令可以發送給多個DBMS服務器分布式事務是通過中間層應用服務器和外部的事務管理器以及JDBC服務器一同進行管理的,中間層的基礎設施的這三個部分提供了plumbing。
分布式事務基礎設施的首要元素是事務管理器,它可以是JTA的具體實現。事務管理器控制著事務邊界以及兩階段提交過程。它啟動和關閉與分布式事務 XAConnection對象相關的組件,并跟蹤那些參與了分布式事務的DBMS服務器。事務管理器在每一個dbms中進行運行決定是否提交事務,僅當所有的dbms都同意提交時,事務管理器才提交事務,否則進行rollback。
分布式事務的另一個元素是支持jdbc api的jdbc驅動程序,而且這個驅動程序必須包含實現XADataSource和XAConnection接口的類。XADataResource接口和DataSource接口類似,但是它創建的對象是XAConnection對象而不是Connection對象。繼承于 PooledConnection的XAConnection對象的特殊在于可以用它來獲取XASource對象。事務管理器使用這個XARource對象開始和結束與分布式事務中的這個XAConnection相關的組件。
分布式事務基礎設施中的第三個部分通常是一個連接池模塊。XAConnection接口從PooledConnection接口繼承而來,這表示分布式事務中的數據庫連接可以來自連接池模塊所管理的連接池。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
