重要提示:本文部分內(nèi)容是斑竹從網(wǎng)上搜集整理而來,如果您認(rèn)為該文檔的內(nèi)容侵犯了您的權(quán)益,請與整理者(excelarthur@yahoo.com.cn)聯(lián)系,與dev2dev網(wǎng)站無關(guān)。
JDBC3.0的特性
1、JDBC3.0規(guī)范中數(shù)據(jù)庫連接池框架
JDBC3.0規(guī)范中通過提供了一個(gè)支持?jǐn)?shù)據(jù)庫連接池的框架,這個(gè)框架僅僅規(guī)定了如何支持連接池的實(shí)現(xiàn),而連接池的具體實(shí)現(xiàn)JDBC 3.0規(guī)范并沒有做相關(guān)的規(guī)定。通過這個(gè)框架可以讓不同角色的開發(fā)人員共同實(shí)現(xiàn)數(shù)據(jù)庫連接池。
通過JDBC3.0規(guī)范可以知道具體數(shù)據(jù)庫連接池的實(shí)現(xiàn)可以分為JDBC Driver級(jí)和Application Server級(jí)。在JDBC Driver級(jí)的實(shí)現(xiàn)中任何相關(guān)的工作均由特定數(shù)據(jù)庫廠商的JDBC Drvier的開發(fā)人員來具體實(shí)現(xiàn),即JDBC Driver既需要提供對(duì)數(shù)據(jù)庫連接池的支持同時(shí)也必須對(duì)數(shù)據(jù)庫連接池進(jìn)行具體實(shí)現(xiàn)。而在Application Server級(jí)中數(shù)據(jù)庫連接池的實(shí)現(xiàn)中特定數(shù)據(jù)庫廠商的JDBC Driver開發(fā)人員和Application Server開發(fā)人員來共同實(shí)現(xiàn)數(shù)據(jù)庫連接池的實(shí)現(xiàn)(但是現(xiàn)在大多數(shù)Application Server廠商實(shí)現(xiàn)的連接池的機(jī)制和規(guī)范中提到有差異),其中特定數(shù)據(jù)庫廠商的JDBC Driver提供數(shù)據(jù)庫連接池的支持而特定的Application Server廠商提供數(shù)據(jù)庫連接池的具體實(shí)現(xiàn)。
JDBC3.0規(guī)范規(guī)定了如下的類和接口來支持?jǐn)?shù)據(jù)庫連接池的實(shí)現(xiàn)。
javax.sql.ConnectionEvent
javax.sql.ConnectionPoolDataSource
javax.sql.PooledConnection
javax.sql.ConnectionEventListener
其中除javax.sql.ConnectionEvent是類,其它的均為接口。
![](http://dev2dev.bea.com.cn/images/image060112002.jpg)
JDBC3.0連接池框架的關(guān)系圖
通過此圖可以大概的了解相關(guān)接口在一個(gè)典型的三層環(huán)境中應(yīng)用程序的位置。
2、檢索自動(dòng)產(chǎn)生的關(guān)鍵字
為了解決對(duì)獲取自動(dòng)產(chǎn)生的或自動(dòng)增加的關(guān)鍵字的值的需求,JDBC 3.0 API 現(xiàn)在將獲取這種值變得很輕松。要確定任何所產(chǎn)生的關(guān)鍵字的值,只要簡單地在語句的 execute() 方法中指定一個(gè)可選的標(biāo)記,表示您有興趣獲取產(chǎn)生的值。您感興趣的程度可以是 Statement.RETURN_GENERATED_KEYS,也可以是 Statement.NO_GENERATED_KEYS。在執(zhí)行這條語句后,所產(chǎn)生的關(guān)鍵字的值就會(huì)通過從 Statement 的實(shí)例方法 getGeneratedKeys() 來檢索 ResultSet 而獲得,ResultSet 包含了每個(gè)所產(chǎn)生的關(guān)鍵字的列,下面的示例創(chuàng)建一個(gè)新的作者并返回對(duì)應(yīng)的自動(dòng)產(chǎn)生的關(guān)鍵字。
……
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、返回多重結(jié)果
JDBC 2 規(guī)范的一個(gè)局限是,在任意時(shí)刻,返回多重結(jié)果的語句只能打開一個(gè)ResultSet。作為 JDBC 3.0 規(guī)范中改變的一個(gè)部分,規(guī)范將允許 Statement 接口支持多重打開的 ResultSets。然而,重要的是 execute() 方法仍然會(huì)關(guān)閉任何以前 execute() 調(diào)用中打開的 ResultSet。所以,要支持多重打開的結(jié)果,Statement 接口就要加上一個(gè)重載的 getMoreResults() 方法。新式的方法會(huì)做一個(gè)整數(shù)標(biāo)記,在 getResultSet() 方法被調(diào)用時(shí)指定前一次打開的 ResultSet 的行為。接口將按如下所示定義標(biāo)記:
CLOSE_ALL_RESULTS:當(dāng)調(diào)用 getMoreResults() 時(shí),所有以前打開的 ResultSet 對(duì)象都將被關(guān)閉。
CLOSE_CURRENT_RESULT:當(dāng)調(diào)用 getMoreResults() 時(shí),當(dāng)前的 ResultSet 對(duì)象將被關(guān)閉。
KEEP_CURRENT_RESULT:當(dāng)調(diào)用 getMoreResults() 時(shí),當(dāng)前的 ResultSet 對(duì)象將不會(huì)被關(guān)閉。
下面展示的是一個(gè)處理多重打開結(jié)果的示例。
……
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、在事務(wù)中使用 Savepoint
也許在 JDBC 3.0 中最令人興奮的附加特點(diǎn)就是 Savepoint 了。JDBC 2 中的事務(wù)支持讓開發(fā)人員可以控制對(duì)數(shù)據(jù)的并發(fā)訪問,從而保證持續(xù)數(shù)據(jù)總是保持一致的狀態(tài)??上У氖牵袝r(shí)候需要的是對(duì)事務(wù)多一點(diǎn)的控制,而不是在當(dāng)前的事務(wù)中簡單地對(duì)每一個(gè)改變進(jìn)行回滾。在JDBC 3.0 下,可以通過 Savepoint 獲得這種控制。Savepoint 接口允許您將事務(wù)分割為各個(gè)邏輯斷點(diǎn),以控制有多少事務(wù)需要回滾。下圖將說明如何在事務(wù)中運(yùn)用 Savepoint。
![](http://dev2dev.bea.com.cn/images/image060112004.jpg)
Savepoint 的直觀表示
你或許不是經(jīng)常需要使用 Savepoint。然而,在一種普遍的情況下 Savepoint 會(huì)發(fā)揮作用,那就是您需要作一系列的改變,但是在知道所有的結(jié)果之前不能確定應(yīng)該保留這些改變的哪一部分。下面的代碼示例說明了如何使用 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)元數(shù)據(jù) API
元數(shù)據(jù) API 已經(jīng)得到更新,DatabaseMetaData 接口現(xiàn)在可以檢索 SQL 類型的層次結(jié)構(gòu),一種新的 ParameterMetaData 接口可以描述 PreparedStatement 對(duì)象中參數(shù)的類型和屬性。
2)CallableStatements 中已命名的參數(shù)
在 JDBC 3.0 之前,設(shè)置一個(gè)存儲(chǔ)過程中的一個(gè)參數(shù)要指定它的索引值,而不是它的名稱。 CallableStatement 接口已經(jīng)被更新了,現(xiàn)在您可以用名稱來指定參數(shù)。
3)數(shù)據(jù)類型的改變
JDBC 所支持的數(shù)據(jù)類型作了幾個(gè)改變,其中之一是增加了兩種新的數(shù)據(jù)類型。
為了便于修改 CLOB(Character Large OBject,字符型巨對(duì)象)、BLOB(Binary Large OBject,二進(jìn)制巨對(duì)象)和 REF(SQL 結(jié)構(gòu))類型的值,同名的數(shù)據(jù)類型接口都被更新了。接下來的是,因?yàn)槲覀儸F(xiàn)在能夠更新這些數(shù)據(jù)類型的值,所以 ResultSet 接口也被修改了,以支持對(duì)這些數(shù)據(jù)類型的列的更新,也包括對(duì) ARRAY 類型的更新。增加的兩種新的數(shù)據(jù)類型是 java.sql.Types.DATALINK 和 java.sql.Types.BOOLEAN。新增的數(shù)據(jù)類型指的是同名的 SQL 類型。DATALINK 提供對(duì)外部資源的訪問或 URL,而 BOOLEAN 類型在邏輯上和 BIT 類型是等同的,只是增加了在語義上的含義。DATALINK 列值是通過使用新的 getURL() 方法從 ResultSet 的一個(gè)實(shí)例中檢索到的,而 BOOLEAN 類型是通過使用 getBoolean() 來檢索的。
二進(jìn)制大對(duì)象Blob
Blob對(duì)象是SQL Blob的Java語言映射。SQL Blob是一個(gè)內(nèi)置類型,它可以將一個(gè)二進(jìn)制大對(duì)象保存在數(shù)據(jù)庫中。接口ResultSet、CallableStatement和PreparedStatement中的方法允許程序員使用與訪問SQL 92內(nèi)置類型同樣的方式來訪問SQL 99類型BLOB。
在標(biāo)準(zhǔn)實(shí)現(xiàn)中,JDBC驅(qū)動(dòng)程序在后臺(tái)使用SQL類型LOCATOR(BLOB)來實(shí)現(xiàn)Blob接口。LOCATOR(BLOB)指向保存在數(shù)據(jù)庫服務(wù)器上的SQL BLOB值,而且這些操作作用在這個(gè)LOCATOR(定位器)上與作用在BLOB值本身有同樣的結(jié)果。這意味著用戶可以在一個(gè)Blob實(shí)例上執(zhí)行操作而不必將這個(gè)BLOB數(shù)據(jù)物化到用戶上,這將顯著的提高性能。因?yàn)轵?qū)動(dòng)程序在后臺(tái)使用LOCATOR(BLOB),所以它的使用對(duì)程序員是完全透明的。
Blob實(shí)例的標(biāo)準(zhǔn)行為一直保持有效,直到這個(gè)事務(wù)(創(chuàng)建一個(gè)Blob的事務(wù))執(zhí)行了提交或者回滾操作。
- 創(chuàng)建Blob對(duì)象
下面的代碼說明了如何創(chuàng)建一個(gè)Blob對(duì)象,其中stmt是一個(gè)Statement對(duì)象: 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包含一個(gè)指向BLOB值的邏輯指針,該BLOB值保存在結(jié)果集rs的第一行的DATA列中。即使變量blob實(shí)際上并不包含BLOB值中的數(shù)值,應(yīng)用程序在blob上執(zhí)行操作仍然像在實(shí)際的數(shù)據(jù)上執(zhí)行一樣。即應(yīng)用程序在blob上所作的任何操作都會(huì)對(duì)表中的BLOB值起作用。
- 物化BLOB數(shù)據(jù)
開發(fā)人員可以在Blob對(duì)象上調(diào)用JDBC API中的方法,就像這些方法直接
在該對(duì)象所指向的SQL BLOB上執(zhí)行操作一樣。然而,如果想在BLOB數(shù)據(jù)上執(zhí)行操作,就必須首先將BLOB數(shù)據(jù)物化到客戶。Blob接口提供了兩個(gè)方法來物化BLOB數(shù)據(jù):getBinaryStream,這個(gè)方法將BLOB數(shù)據(jù)物化為一個(gè)輸入流;getBytes,這個(gè)方法將BLOB值得一部分或者全部物化為一個(gè)字節(jié)數(shù)組。下面的代碼說明了如何將Blob所指向的BLOB值得全部物化為一個(gè)輸入流: java.io.InputStream in = blob.getBinaryStream();
byte b;
while((b = in.read()) >-1){
System.out.println(b);
}
接下來的代碼同樣物化了blob所指向的BLOB值得所有數(shù)據(jù),但是它產(chǎn)生的是字節(jié)數(shù)組而不是輸入流。 long len = blob.length();
byte [] data = blob.getBytes(1,len);
for(int i=0;ilen;i++){
byte b = data[i];
System.out.println(b);
}
變量data復(fù)制了blob所指向的BLOB值的所有字節(jié)。這是因?yàn)閭鬟f給方法getBytes的參數(shù)值說明了整個(gè)BLOB值:第一個(gè)參數(shù)表示從第一個(gè)字節(jié)開始返回字節(jié),第二個(gè)參數(shù)說明它返回的字節(jié)長度是BLOB值的長度。
需要說明的是,因?yàn)镾QL和Java語言之間的不同,一個(gè)BLOB值得第一個(gè)字節(jié)在位置1,而Java數(shù)組的第一個(gè)元素的索引是0。
- 存儲(chǔ)Blob值
若要在數(shù)據(jù)庫中存儲(chǔ)Blob值,應(yīng)用程序可以把它作為一個(gè)參數(shù)傳遞給
PreparedStatement的方法setBlob。下面的代碼就實(shí)現(xiàn)了這個(gè)功能:PreparedStatement的方法setBlob。下面的代碼就實(shí)現(xiàn)了這個(gè)功能:
Blob stats = rs.getBlob(“STATS”);
PreparedStatement pstmt= con.preparedStatement(
“UPDATE SIGHTINGS SET MEAS= ? WHERE AREA = ‘BEIJING' ”);
pstmt.setBlob(1,stats);
pstmt.excuteUpdate();
- 發(fā)現(xiàn)Blob對(duì)象中的模式
如果一個(gè)Blob對(duì)象包含一個(gè)給定的字節(jié)集合,應(yīng)用程序可以使用方法
position的兩個(gè)方法來找到它。其中一個(gè)方法搜索一個(gè)給定的字節(jié)數(shù)組,而另一個(gè)在一個(gè)Blob對(duì)象中搜索一個(gè)給定的Blob對(duì)象。如果發(fā)現(xiàn)一個(gè)匹配的結(jié)果,則返回該模式字節(jié)的起始位置。
- 修改Blob對(duì)象的方法
JDBC 3.0 API中新增的方法setBytes和setBinaryStream允許應(yīng)用程序?qū)?BR> Blob對(duì)象進(jìn)行修改。
方法setBytes有兩個(gè)方法來向Blob對(duì)象添加數(shù)據(jù)。其中一個(gè)方法增加給定的字節(jié)數(shù)組的全部內(nèi)容,而另一個(gè)方法增加給定字節(jié)數(shù)組的特定部分。兩個(gè)方法都使用一個(gè)參數(shù)說明向Blob對(duì)象插入數(shù)據(jù)的起始位置。例如,下面的代碼段在一個(gè)Blob對(duì)象blob1的第一個(gè)字節(jié)處寫入整個(gè)字節(jié)數(shù)組bytes。在這種情況下,bytes包含了Blob對(duì)象blob的所有字節(jié),因此執(zhí)行的結(jié)果是blob2被寫入了blob1的起始處。需要注意的是如果blob2的長度是1024字節(jié),那么blob2的1024各字節(jié)將覆蓋blob1的開頭的1024各字節(jié)。 byte [] bytes = blob2.getBytes(1,blob2.length());
blob.setBytes(1,bytes,0,512);
下面的代碼段說明如何僅僅向Blob對(duì)象加入一個(gè)字節(jié)數(shù)組的特定部分。在這種情況下,方法setBytes接受兩個(gè)附加的參數(shù)來說明需要增加字節(jié)數(shù)組的哪一個(gè)部分。其中一個(gè)參數(shù)指明了這個(gè)字節(jié)數(shù)組的起始偏移量,另一個(gè)參數(shù)說明這個(gè)字節(jié)數(shù)組包含多少個(gè)連續(xù)的字節(jié)。byte [] bytes={……};
blob.setBytes(1,bytes,0,512);
除了可以向Blob對(duì)象增加字節(jié)之外,Blob接口還提供了刪除字節(jié)的方法。方法truncate接受一個(gè)字節(jié)數(shù)目作為一個(gè)參數(shù)并且根據(jù)這個(gè)數(shù)目來縮短Blob對(duì)象。
- 定位器和更新
在標(biāo)準(zhǔn)實(shí)現(xiàn)中,指向SQL BLOB的Blob對(duì)象使用了SQL LOCATOR類型。定位器(locator)是一個(gè)指向保存在數(shù)據(jù)庫中的BLOB值的指針,而DBMS如何更新一個(gè)作為定位器實(shí)現(xiàn)的對(duì)象則依賴于具體的數(shù)據(jù)庫。某些DBMS會(huì)更新表中的BLOB值,而另一些則僅僅更新BLOB值的一個(gè)副本,并不改變數(shù)據(jù)庫中的值。在后一種情況下,應(yīng)用程序必須直接更新BLOb值。
為了發(fā)現(xiàn)DBMS是如何更新BLOB值的,應(yīng)用程序可以調(diào)用DatabaseMetaData的方法locatorsUpdateCopy。如果這個(gè)方法返回true,則應(yīng)用程序必須自己更新數(shù)據(jù)庫中的BLOB值。下面的代碼顯示了這個(gè)過程:首先從rs取回Blob對(duì)象,然后把它的值改為字節(jié)數(shù)據(jù)val的值。如果方法locatorsUpdateCopy返回true,那么它隨后執(zhí)行一個(gè)PreparedStatement對(duì)象來更新數(shù)據(jù)庫中的值。如果方法locatorsUpdateCopy返回false,代碼什么也不用做,因?yàn)閿?shù)據(jù)庫中的值已經(jīng)被更新過了。 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();
}
字符大對(duì)象Clob
- 創(chuàng)建Blob對(duì)象
Clob clob = rs.getClob(1);
變量clob現(xiàn)在可以被用于在CLOB值上執(zhí)行操作,而假設(shè)這CLOB值保存在結(jié)果集rs的第一列中。
- 物化Clob數(shù)據(jù)
和物化Blob的方式一樣。不過Clob接口提供了三種方法達(dá)到將CLOB作為一個(gè)Java對(duì)象的形式保存在客戶的內(nèi)存中。 使用getAsiiStream把CLOB值物化為一個(gè)包含Ascii字節(jié)的字符流。
① 使用getAsiiStream把CLOB值物化為一個(gè)包含Ascii字節(jié)的字符流。
Clob notes = rs.getClob(“NOTES”);
java.io.InputStream in = notes.getAsciiStream();
byte b = in.read();
② 使用getCharacterStream把CLOB值物化為一個(gè)Unicode字符流。
Clob notes = rs.getClob(“NOTES”);
java.io.Reader reader = notes.getCharacterStream();
int c = reader.read();
//
③ 使用getSubString將CLOB值的全部或者部分化為一個(gè)String對(duì)象。
Clob notes = rs.getClob(4);
String substring= notes.getSubString(10,5);
或者
long len =notes.length();
String substring = notes.getSubString(1,(int)len);
- 存儲(chǔ)、更新Clob對(duì)象
和存儲(chǔ)、更新Blob對(duì)象類似。
元數(shù)據(jù)接口使用詳解
三個(gè)元數(shù)據(jù)接口DatabaseMetaData、ResultSetMetaData和ParameterMetaData接口是三個(gè)常用的元數(shù)據(jù)接口。DatabaseMetaData提供與數(shù)據(jù)庫或者DBMS相關(guān)的信息;ResultSetMetaData對(duì)象提供與特定ResultSet實(shí)例中與列相關(guān)的信息;ParameterMetaData對(duì)象提供與PreparedStatement對(duì)象的參數(shù)有關(guān)的信息。本文討論的內(nèi)容并不僅限于JDBC的某個(gè)版本,而是基于1.0—3.0的規(guī)范進(jìn)行學(xué)習(xí)。
- ResultSetMetaData對(duì)象
當(dāng)在JDBC應(yīng)用程序中發(fā)送select語句時(shí),該操作會(huì)返回一個(gè)ResultSet對(duì)象,這個(gè)ResultSet對(duì)象包含滿足條件的數(shù)據(jù)。通過創(chuàng)建ResultMetaData對(duì)象和調(diào)用該對(duì)象的方法,可以獲取與這個(gè)ResultSet對(duì)象中的列有關(guān)的信息。下面的代碼段將創(chuàng)建ResultSet對(duì)象rs,然后使用rs來創(chuàng)建ResultSetMetaData對(duì)象,所創(chuàng)建的ResultSetMetaData對(duì)象包含與rs中的列有關(guān)的信息。 Statement stmt= con . createStatement();
ResultSet rs = stmt.executeQuery(“select * from sales”);
ResultSetMetaData rsmd = rs.getMetaData();
現(xiàn)在可以使用rsmd調(diào)用ResultSetMetaData的方法來訪問與rs中的列有關(guān)的信息。除了方法getColumnCount給出結(jié)果集中總的列數(shù)外,所有的ResultSetMetaData方法都返回與單個(gè)列有關(guān)的信息,并都接受一個(gè)表示對(duì)應(yīng)列號(hào)的參數(shù)。
- getColumnCount方法
這也許是ResultSetMetaData中使用最多的方法,該方法返回結(jié)果集中列數(shù)目?。?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。當(dāng)不知道每一列的類型,這是比較容易的方法;如果希望能檢索所有的數(shù)據(jù)類型(包括SQL 99數(shù)據(jù)型),則可以使用方法getObject,這是保證能夠檢索所有列值得唯一方法。
- 獲取列類型信息
有兩個(gè)ResultSetMetaData方法可以獲取與結(jié)果集列的類型有關(guān)的信息。這
兩個(gè)方法是getColumnType和getColumnTypeName。getColumnType方法用于確定存儲(chǔ)在指定列中的值的JDBC類型。該方法以一個(gè)int值來返回JDBC類型。如下面的代碼獲得rs第二列的JDBC類型: ResultSetMetaData rsmd = rs.getMetaData();
int jdbcType = rsmd.getColumnType(2);
- 獲取其他信息
另外有幾個(gè)方法用來提供與存儲(chǔ)數(shù)值類型的列有關(guān)的信息。isAutoIncrement
isCurrency
isSigned
getPrecision
getScale
isNullable
getColumnDisplaySize
- 使用DatabaseMetaData對(duì)象
接口DatabaseMetaData提供了大量的方法取得與數(shù)據(jù)庫相關(guān)的信息。一旦獲得了打開的連接,就可以創(chuàng)建包含與數(shù)據(jù)庫系統(tǒng)有關(guān)的信息的DatabaseMetaData對(duì)象。
- DatabaseMetaData方法的類別
按照返回值的類型對(duì)DatabaseMetaData的方法進(jìn)行分類,可以分為4種。
有三種類型返回單一的值,另外一種返回一個(gè)結(jié)果集,這個(gè)結(jié)果集包含1~18列的數(shù)據(jù)。 ① 返回String的方法
最小的類別是指返回String對(duì)象的DatabaseMetaData方法。這些方法中的一些方法可以獲取與DBMS有關(guān)的總體信息,包括數(shù)據(jù)庫的URL、username、產(chǎn)品名稱、驅(qū)動(dòng)程序信息等等。
② 返回int的方法
③ 返回boolean的方法
④返回ResultSet對(duì)象的方法
這些方法可以返回ResultSet對(duì)象,所返回的ResultSet對(duì)象可以包含1到最多18列。
- 獲取與主外鍵有關(guān)的信息
返回與主外鍵有關(guān)信息的方法主要有g(shù)etPrimaryKeys、getImportedKeys、getExportedKeys以及getCrossReference等。
下面的代碼段顯示了如果在定義表時(shí)指定了主鍵,則可以調(diào)用方法getPrimaryKeys開獲取對(duì)于表中主鍵列的描述。 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等將詳細(xì)描述每一列。列key_seq中的值表示描述的是哪一列。
- 使用ParameterMetaData對(duì)象
可以使用ParameterMetaData對(duì)象來獲取與PreparedStatement對(duì)象或者CallableStatement對(duì)象有關(guān)的信息。這些參數(shù)由”?”占位符表示,”?”占位符是提供給Connection方法prepareStatement和prepareCall的SQL語句。下面的代碼行使用兩個(gè)參數(shù)占位符來創(chuàng)建一個(gè)PreparedStatement對(duì)象。
PreparedStatement pstmt=con.prepareStatement(“select id from employees where dept=? and salary>?”);
這些參數(shù)根據(jù)其序號(hào)來編號(hào),因此第一個(gè)參數(shù)編號(hào)1,第二個(gè)參數(shù)編號(hào)2,依此類推。在上面的代碼行中,參數(shù)1是列dept中的一個(gè)值,參數(shù)2是salary中的一個(gè)值。下面的代碼段用于找出PreparedStatement pstmt有多少個(gè)參數(shù)。首先創(chuàng)建pstmt并用它來創(chuàng)建ParameterMetaData對(duì)象pmd,這個(gè)對(duì)象包含與pstmt中的參數(shù)有關(guān)的信息。接著調(diào)用pmd上的方法getColumnCount來找出pstmt有多少參數(shù)。
PreparedStatement pstmt=con.prepareStatement(
“update employees set salary =? Where level=?”);
ParameterMetaData pmd = pstmt.getParameterMetaData();
int count=pmd.getParameterCount();
變量count的值應(yīng)該等于2。方法getParameterCount不接受參數(shù),因?yàn)樗祷嘏cPreparedStatement對(duì)象的所有參數(shù)有關(guān)的信息。ParameterMetaData接口中的所有其他方法都接受序號(hào)來表示作為要查詢的信息的參數(shù)。
- JDBC 3.0API中新增的方法示例
JDBC 3.0 API引入了這樣一種應(yīng)用功能,即決定在已經(jīng)調(diào)用commit方法來終止事務(wù)之后,ResultSet對(duì)象是否仍舊打開。這個(gè)功能即為結(jié)果集可保持性。ResultSet中加入了兩個(gè)域HOLD_CURSORS_OVER_COMMIT和 CLOSE_CURSORS_AT_COMMIT,這些域可以用于指定ResultSet對(duì)象的可保持性,這些常量可以提供給創(chuàng)建Statement、PreparedStatement和CallableStatement對(duì)象的Connection方法,還可以作為提供給DataBaseMetaData方法supportResultSetHoldability的可能的參數(shù)值。
在下面的代碼段中,首先判斷驅(qū)動(dòng)程序是否支持ResultSet可保持性,如果支持,則接著創(chuàng)建會(huì)生成帶有可保持性游標(biāo)的ResultSet對(duì)象的Statement對(duì)象,另外此代碼還指定了stmt在執(zhí)行查詢時(shí)產(chǎn)生的ResultSet對(duì)象的類型和并發(fā)模式。
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);
}
參考《JDBC API Reference》 Maydene Fisher etc. 著
RowSet
RowSet對(duì)象是表格式數(shù)據(jù)的容器,封裝了一組從數(shù)據(jù)源獲取得數(shù)據(jù)行。在RowSet接口的基本實(shí)現(xiàn)中是從JDBC數(shù)據(jù)源中獲取數(shù)據(jù)行。由于行集是可以定制的,所以行集中的數(shù)據(jù)可以來自電子數(shù)據(jù)表、flat文件(平面文件?)或者其他任何表格式樣的數(shù)據(jù)源。RowSet對(duì)象是ResultSet接口的擴(kuò)展,這就意味著RowSet對(duì)象是可滾動(dòng)的、可更新的,并且能夠執(zhí)行ResultSet對(duì)象可以執(zhí)行的任何操作。
RowSet對(duì)象不同于ResultSet對(duì)象,它是JavaBean組件,因此,該對(duì)象有JavaBean屬性,并遵循其事件模型。另外RowSet對(duì)象的屬性也允許該對(duì)象建立自己的數(shù)據(jù)庫連接,執(zhí)行自己的查詢。此外,RowSet可以是disconnected的,也就是說使用行集的過程中,不必一直保持到數(shù)據(jù)源的打開連接。另外,行集可以串行化,所以可以通過網(wǎng)絡(luò)把它發(fā)送到遠(yuǎn)程對(duì)象中去。
通常情況下,JDBC API可以分為兩類:RowSet部分和驅(qū)動(dòng)程序部分。RowSet以及支持它的接口使用其他JDBC API實(shí)現(xiàn)。從邏輯上來說,可以把實(shí)現(xiàn)RowSet接口的類看作是執(zhí)行在JDBC驅(qū)動(dòng)程序的上一層的軟件。
現(xiàn)在的J2SE 5.0中,可以把JDBC API分為三種類別,除了上面的兩類,還有RowSet接口的5種標(biāo)準(zhǔn)實(shí)現(xiàn)。這些實(shí)現(xiàn)提供了一組接口,以擴(kuò)展基本的RowSet接口,通過在這些接口上建立application,可以確保在事件處理、游標(biāo)控制以及其他操作方面的實(shí)現(xiàn)遵循JDBC API。
RowSet接口提供了一組基本方法,這些方法對(duì)于所有行集都是通用的。因?yàn)樗械腞owSet對(duì)象都是JavaBean組件,因此,RowSet接口具有添加和刪除event listener的方法,也有g(shù)et/set RowSet對(duì)象所有屬性的方法。RowSet對(duì)象的大多數(shù)屬性都支持建立連接或者執(zhí)行命令。為了執(zhí)行查詢、更新等SQL語句,并生成能夠從中獲取數(shù)據(jù)的結(jié)果集,行集會(huì)使用到數(shù)據(jù)源的連接。
若一個(gè)組件希望得到在RowSet對(duì)象上發(fā)生的事件的通知,它就應(yīng)該實(shí)現(xiàn)RowSetListener接口,并向RowSet對(duì)象進(jìn)行注冊。這就是listener,一個(gè)GUI組件。這樣每當(dāng)行集產(chǎn)生事件時(shí),listener每次都會(huì)得到事件的通知,這樣就能夠保持它的游標(biāo)位置和數(shù)據(jù)與行集的內(nèi)容一致。
RowSetInternal、RowSetReader、和RowSetWriter接口支持行集的reader/weiter工具。reader是一個(gè)實(shí)現(xiàn)RowSetReader接口的類的實(shí)例,用來讀取數(shù)據(jù)并數(shù)據(jù)插入到行集中。writer是一個(gè)實(shí)現(xiàn)RowSetWriter接口的類的實(shí)例,用來將修改后的數(shù)據(jù)寫回到數(shù)據(jù)源。reader和writer就像是listener一樣,都向行集進(jìn)行動(dòng)態(tài)注冊。
調(diào)用reader或者writer的RowSet對(duì)象必須是實(shí)現(xiàn)RowSetInternal接口的類的實(shí)例。這個(gè)接口為reader或者writer提供了附加的方法,用來操作行集的內(nèi)部狀態(tài)。例如行集可以跟蹤它的初始值,RowSetInternal方法允許writer檢測數(shù)據(jù)源中的相應(yīng)數(shù)據(jù)是否已經(jīng)被其他用戶修改。另外,能夠使用RowSetInternal方法來獲取為行集的命令字符串設(shè)置的輸入?yún)?shù),也能夠獲取傳遞給行集的連接。最后,RowSetInternal方法允許reader設(shè)置新的RowSetMetaData對(duì)象,這個(gè)對(duì)象用來為行集描述reder將要插入到該行集中的數(shù)據(jù)行。
行集可以是connected的,也可以是disconnected的,一個(gè)連接的RowSet對(duì)象,在使用的整個(gè)過程中保持到數(shù)據(jù)源的連接,而一個(gè)未連接的行集,只有從數(shù)據(jù)源讀取數(shù)據(jù)或者將數(shù)據(jù)寫回?cái)?shù)據(jù)源時(shí)才會(huì)連接到它的數(shù)據(jù)源。若行集是未連接的,它就不需要JDBC驅(qū)動(dòng)或者JDBC API的完整實(shí)現(xiàn)。這使得它非常小巧,因此也成為發(fā)送一組數(shù)據(jù)到一個(gè)thin client的理想的容器。這個(gè)客戶端可以選擇更新數(shù)據(jù),并將行集發(fā)送回應(yīng)用服務(wù)器。在服務(wù)器端,未連接的RowSet對(duì)象使用它的reader來建立到數(shù)據(jù)源的連接,并把數(shù)據(jù)寫回?cái)?shù)據(jù)源。這一操作的具體實(shí)現(xiàn)依賴于reader的實(shí)現(xiàn)方式。通常reader將建立連接與讀/寫數(shù)據(jù)的操作委托給JDBC驅(qū)動(dòng)。
行集的事件模型
行集事件模型使得Java對(duì)象或者組件能夠收到RowSet對(duì)象產(chǎn)生的事件的通知。通知機(jī)制的建立包括被通知的組件,也包括RowSet對(duì)象自身。首先,每一個(gè)希望得到事件通知的組件都必須實(shí)現(xiàn)RowSetListener接口。然后,RowSet對(duì)象必須注冊每一個(gè)組件,這通過在RowSet對(duì)象的事件通知組件列表中添加這些組件來完成。在這種情況下,這樣的組件是一個(gè)listener,它是一個(gè)實(shí)現(xiàn)RowSetListener方法的類的實(shí)例,并已經(jīng)向RowSet對(duì)象進(jìn)行過注冊。
在RowSet對(duì)象中可能發(fā)生三種事件:游標(biāo)移動(dòng)、數(shù)據(jù)行發(fā)生變化(ins、del、upd)或者該對(duì)象的整個(gè)內(nèi)容發(fā)生變化。RowSetListener接口的cursorMoved、rowChanged和rowSetChanged方法分別對(duì)應(yīng)與這些事件。當(dāng)事件發(fā)生時(shí),行集將創(chuàng)建一個(gè)RowSetEvent對(duì)象,使用這個(gè)對(duì)象將該行集標(biāo)識(shí)為事件源。在每一個(gè)listener上調(diào)用適當(dāng)?shù)腞owSetListender方法,并向此方法傳遞一個(gè)RowSetEvent對(duì)象作為輸入?yún)?shù),就將事件通知給行集所有的listener。
RowSet屬性
RowSet接口提供了一組JavaBeans屬性,可以配置RowSet實(shí)例以連接到數(shù)據(jù)源并獲取數(shù)據(jù)行集合。有些屬性可能并不需要,這取決于特定實(shí)現(xiàn)。如用URL或者數(shù)據(jù)源名來建立連接,但只要設(shè)置了其中一個(gè)屬性,另一個(gè)屬性就是可選的。如果設(shè)置了兩個(gè)屬性,就會(huì)使用最近設(shè)置的那個(gè)屬性。若行集的數(shù)據(jù)是從不支持名命令的非SQL數(shù)據(jù)源中如電子表格中獲取的,那么就不需要設(shè)置命令屬性。
幾個(gè)接口的講解
- WebRowSet
WebRowSet接口擴(kuò)展了CacheRowSet接口。相比CacheRowSet接口,增加了讀寫XML格式行集的能力。WebRowSetImpl對(duì)象使用WebRowSetXmlReader對(duì)象來讀取XML格式的行集,使用WebRowSetXmlWriter對(duì)象向XML格式的行集中寫入數(shù)據(jù)。XML版本包含WebRowSetSetImpl對(duì)象的元數(shù)據(jù),同時(shí)也包含它自己的數(shù)據(jù)。 WebRowSetImpl對(duì)象和CachedRowSetImpl相似點(diǎn)是二者都將瘦客戶端連接到應(yīng)用服務(wù)器。所以它們都適合為瘦客戶提供數(shù)據(jù);不同的地方是二者使用的協(xié)議。前者使用http/xml協(xié)議與中間層進(jìn)行通信,而后者使用RMI/IIOP。
- JoinRowSet
JoinRowSet對(duì)象使得程序員能夠從兩個(gè)不同的RowSet對(duì)象合并數(shù)據(jù)。當(dāng)相關(guān)聯(lián)(p/f keys相關(guān)或者其他列唯一對(duì)應(yīng))的數(shù)據(jù)存儲(chǔ)在不同的數(shù)據(jù)源中時(shí),這種合并數(shù)據(jù)的功能很有用。任何RowSet實(shí)現(xiàn)都可以參與合并,但通常情況下,連接的雙方是兩個(gè)CachedRowSetImpl對(duì)象。將相關(guān)數(shù)據(jù)合并到一個(gè)JoinRowSetImpl對(duì)象中,應(yīng)用程序就能夠處理任何其他類型的RowSet對(duì)象一樣來處理這些數(shù)據(jù)。
假設(shè)有兩個(gè)表:employees表和bonus_plan表,兩表的第一個(gè)數(shù)據(jù)列都是ID,這個(gè)數(shù)據(jù)列是主鍵,現(xiàn)要將兩表的信息進(jìn)行匹配合并: 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對(duì)象是可以用于分布式事務(wù)的PooledConnection對(duì)象。它表示數(shù)據(jù)庫的物理連接,多層結(jié)構(gòu)中的服務(wù)器可以用它來創(chuàng)建返回給應(yīng)用程序的Connection對(duì)象。因?yàn)槭峭ㄟ^擴(kuò)展PooledConnection接口得到的,所以繼承了其所有的方法,另外添加了自己的方法 getXAResource。
分布式事務(wù)中的命令可以發(fā)送給多個(gè)DBMS服務(wù)器分布式事務(wù)是通過中間層應(yīng)用服務(wù)器和外部的事務(wù)管理器以及JDBC服務(wù)器一同進(jìn)行管理的,中間層的基礎(chǔ)設(shè)施的這三個(gè)部分提供了plumbing。
分布式事務(wù)基礎(chǔ)設(shè)施的首要元素是事務(wù)管理器,它可以是JTA的具體實(shí)現(xiàn)。事務(wù)管理器控制著事務(wù)邊界以及兩階段提交過程。它啟動(dòng)和關(guān)閉與分布式事務(wù) XAConnection對(duì)象相關(guān)的組件,并跟蹤那些參與了分布式事務(wù)的DBMS服務(wù)器。事務(wù)管理器在每一個(gè)dbms中進(jìn)行運(yùn)行決定是否提交事務(wù),僅當(dāng)所有的dbms都同意提交時(shí),事務(wù)管理器才提交事務(wù),否則進(jìn)行rollback。
分布式事務(wù)的另一個(gè)元素是支持jdbc api的jdbc驅(qū)動(dòng)程序,而且這個(gè)驅(qū)動(dòng)程序必須包含實(shí)現(xiàn)XADataSource和XAConnection接口的類。XADataResource接口和DataSource接口類似,但是它創(chuàng)建的對(duì)象是XAConnection對(duì)象而不是Connection對(duì)象。繼承于 PooledConnection的XAConnection對(duì)象的特殊在于可以用它來獲取XASource對(duì)象。事務(wù)管理器使用這個(gè)XARource對(duì)象開始和結(jié)束與分布式事務(wù)中的這個(gè)XAConnection相關(guān)的組件。
分布式事務(wù)基礎(chǔ)設(shè)施中的第三個(gè)部分通常是一個(gè)連接池模塊。XAConnection接口從PooledConnection接口繼承而來,這表示分布式事務(wù)中的數(shù)據(jù)庫連接可以來自連接池模塊所管理的連接池。
![](http://dev2dev.bea.com.cn/images/_.gif)
作者簡介 |
|
dev2dev ID: lhbing, dev2dev論壇版主,WebLoigc以及Java技術(shù)愛好者 |