[譯]JDBC4.0具有哪些新特性?
在
Java SE 6
所提供的諸多新特性和改進中,值得一提的是為
Java
程序提供數據庫訪問機制的
JDBC
版本升級到了
4.0,
這個以
JSR-221
為代號的版本
,
提供了更加便利的代碼編寫機制及柔性
,
并且支持更多的數據類型
.
在本文中,我們將從編碼的易用性及柔性的角度探討
JDBC 4.0
所帶來的新特性及改進。
JDBC 4.0
的新特性
JDBC 4.0
文檔列舉了
20
個改進及新特性
,
大小不等
.
本文無法做到盡述其詳
,
為此筆者根據其功能特點及應用領域將其分為下述四類:
1.
驅動及連接管理
2.
異常處理
3.
數據類型支持
4.
API
的變化
下面按照上述四類展開詳述:
驅動及連接管理
驅動及連接的使用和結果集管理
—
在
JDBC
的很多地方都發生了顯著的變化
連接數據庫變得更加容易
如果您曾經有過
JDBC
開發的經驗
,
那么我確信您還保存著一份建立數據庫連接所必須的工作列表
.
而列表中的第一項即加載一個合適的驅動程序
.
您是否想過這個步驟應該被改進呢
?
在此版
JDBC
中做到了
.
您不必再顯式地加載
Class.forName
了
.
當您的程序首次試圖連接數據庫時
,
DriverManager
自動加載驅動到當前應用的
CLASSPATH
.
這是
JDBC
的一個比較大的改動
.
盡管
DriverManager
現在可以自動地加載驅動
,
建立一個
DataSource
對象
仍是獲取連接的推薦的方法
.
因為可以在配置中將數據源指向不同的數據庫,
DataSource
更具透明性和靈活性。
這樣就可以訪問另一個數據庫實例不需更改現有的任意一行代碼
,
甚至數據庫的驅動完全不同也沒有關系
.
ResultSet
的使用變得更為靈活
ResultSet
接口的層次結構當前為編程的靈活性提供了一些新的機制
.
RowSet
子接口滾動、可提交并可離線編輯的
ResultSet
.
WebRowSet
子接口提供了從數據庫表中獲取數據
,
并將其序列化為
XML
文檔
,
抑或是將
XML
解析成
result set
的能力
.
盡管上個版本的
JDBC
也提供了
RowSet
接口層次
,當前的版本對于
SQLXML
數據類型支持得更好
(
稍后討論
)
,這些特性是的
JDBC
編程更加容易且具靈活性
.
提供了更多的
API
本版
JDBC
提供了更多的
API
以實現訪問
SQL:2003
具備的新特性
.
此外
,
為了更好的操縱修改數據,
JDBC
也增添了許多的方法。
.
現在我們來看一些代碼并討論下面
Example1
類的輸出結果
.
它將連接嵌入式的
Apache Derby
數據庫并在控制臺上顯示輸出結果
.
盡管
JDBC 4.0
已推出幾個月了
,
筆者發現只有
Apache Derby
提供了支持
JDBC 4.0
規范的驅動
(
截至
2007
年
3
月
).
本文的所有例子均用
JDK 1.6
和
Apache Derby
數據庫
10.2.2.0
開發
.
public class Example1 {
public static void main(String[] args) {
...
String dbName = "example1";
String tableName = "stu1";
ds = new EmbeddedDataSource40();
ds.setDatabaseName(dbName);
String connectionURL = "jdbc:derby:"+dbName+";create=true";
try {
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select * from "+tableName);
int colCount= rs.getMetaData().getColumnCount();
for (int j=0; j< colCount; j++){
System.out.print(rs.getMetaData().getColumnName(j+1)
+ "\t");
}
while (rs.next()) {
System.out.print("\n");
for (int i = 0; i < colCount; i++) {
System.out.print(rs.getString(i + 1) + "\t");
}
}
} catch (SQLException e) {
e.printStackTrace();
}
finally{
//close connections
}
}
}
如果在
example1
數據庫的
stu1
表中有數據的話
,
編譯并運行
Example1.java
將在控制臺獲得以下輸出:
ID NAME COURSE
1001 John Doe Statistics
1002 Jack McDonalds Linear Algebra
如果想看
DriverManager
如何自動加載
JDBC
驅動
,
可以將
Example1
中的:
con=ds.getConnection()
替換為:
con=DriverManager.getConnection(connectionURL)
.
該類將產生相同的輸出。正如您所看到的,再也不用顯式地調用
Class.forName()
了
.
異常處理
怎樣辨別一個
Java
程序的健壯與否呢
?
在我看來,異常處理機制是重要的考慮因素之一
.
一個健壯的
Java
程序可以很好地處理異常
,
并給予程序在發生異常時恢復的能力
.
而一個不健壯的程序將導致輸出錯誤的結果甚至導致整個應用的崩潰
!
JDBC 4.0
增加了一些簡單而有力的異常處理機制
,
其中值得一提的是鏈式異常,如果這個異常鏈存在的話,即可應用增強了的
for
-
each
循環來獲取異常鏈
,.
下面的
Example2
類的局部結構展示了如何應用這種新的方法處理鏈式異常:
public class Example2 {
public static void main(String[] args) {
String dbName = "example";
String tableName = "student4";
try {
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select * from " + tableName);
} catch (SQLException sx) {
for(Throwable e : sx ) {
System.err.println("Error encountered: " + e);
}
}
finally{
//close connections
}
}
}
運行
Example2.java
,
注意
student4
并不是數據庫中實際存在的表
.
將在下列調用中產生鏈式異常:
rs = stmt.executeQuery("select * from " + tableName);
在實際的應用中,需要捕捉到這些異常
,
檢測并進行相應的處理
.
在本例中,筆者僅將其在控制臺輸出
.
以下是輸出代碼:
for(Throwable e : sx ) {
System.err.println("Error encountered: " + e);
}
以下是類
Example2
輸出的結果
:
Error encountered: java.sql.SQLSyntaxErrorException:
Table/View 'STUDENT4' does not exist.
Error encountered: java.sql.SQLException:
Table/View 'STUDENT4' does not exist.
Exception in thread "main" java.lang.NullPointerException
at ex.Examlpe2.main(Examlpe2.java:51)
通過應用
JDBC 4.0,
您現在不需太多代碼即可以獲取及遍歷異常鏈
.
在以往的版本中
,
您在遍歷異常鏈時,必須手工的調用
getNextException
方法才能得到相同的效果
.
支持的數據類型
本版
JDBC
增加了一些新的數據類型,對其他的一些數據類型,則提供了更好的支持
.
筆者為
XML
被正式支持感到欣喜
,
本版中產生了一個新的接口
:
SQLXML
.
在筆者看來這個接口值得單獨開一個章節為其討論:
SQLXML
與
XML
的支持
SQLXML
是
SQL
中
XML
數據類型在
Java
中的表示,
XML
是
SQL
中用于表示表中
XML
數據的內建數據類型
.
在默認的情況下,
JDBC
驅動將
SQLXML
指針指向
XML
數據而不是數據本身
.
SQLXML
對象在其被創建的事務中是穩定的
.
在下面的
Example3
類中
,
筆者將說明如何在當前連接中應用
SQLXML
并更新表數據
.
public class Example3 {
public static void main(String[] args) {
...
con = ds.getConnection();
SQLXML sx= con.createSQLXML();
sx.setString("Math is Fun");
String psx ="insert into "+tableName+
" ( id, textbook) values(?,?) ";
PreparedStatement pstmt = con.prepareStatement(psx);
pstmt.setString(1,"1000");
pstmt.setSQLXML(2,sx);
pstmt.executeUpdate();
...
}
}
這個例子說明了您所能應用的最簡單的情況
.
如果我們繼續深入研究,事情就會變得有趣得多了
.
但在我們深入討論之前
,
讓我來告訴您運行
Example3.java
.
的結果。
非常不幸
,
我無法獲取到
SQLXML
對象,并得到了以下讓人失望的輸出:
java.sql.SQLFeatureNotSupportedException: Feature not
implemented: no details.
at org.apache.derby.impl.jdbc.SQLExceptionFactory40.
getSQLException(Unknown Source)
... ... ... ...
at ex.Example3.main(Example3.java:62)
看來
Apache Derby
并沒有提供從
Connection
中獲取
SQLXML
對象的方法
.
但至少您可以看到筆者正試圖在類
Example3
中實現的東西
:
我想插入一行新的數據:
id
列值為
1000
textbook
列
(S
QLXML
類型
)
插入
Math is Fun
.
筆者用如下代碼段結束關于
SQLXML
的討論,這段代碼從數據庫中讀取
XML
值并將其轉化為
Document
對象
.
SQLXML sqlxml = rs.getSQLXML(column);
InputStream binaryStream = sqlxml.getBinaryStream();
DocumentBuilder parser =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = parser.parse(binaryStream);
可以把一個列的值直接轉化為
XML
文檔不是一件令人興奮的事情嗎
?
我覺得這個特性非常好
.
ROWID
數據類型
SQL
ROWID
唯一標識了數據表中的一行,并是訪問該行的最快的方法,
本版增加了
RowId
接口以提供對
ROWID
SQL
數據類型在
Java
類中的支持
.
對大對象類型支持的增強
JDBC
版本
2
提供了對大的
SQL
對象如:
CLOB
,
BLOB
,
ARRAY
的支持
,
及用于添加相關接口的
Struct:
Clob
,
Blob
,
Array
, and
Struct
.
在本版的
JDBC
中增加了很多對這些對象訪問的新方法
.
筆者將在
API
變化一節中進行詳細論述
.
支持
National Character Set
(
NCS
)
轉化
SQL:2003
提出了如下
SQL
數據類型的支持:
NCHAR
,
NVARCHAR
,
LONGNVARCHAR
,
及
NCLOB
.
其功用和
CHAR
,
VARCHAR
,
LONGVARCHAR
,
及
CLOB
類似
,其區別僅是,這些類型的文本是用
NCS
編碼的。
如果需要大量的字符處理,您可能更傾向于
NCS
數據類型而非普通的數據類型。本版
JDBC
提供了增強對
NCS
支持的
API.
-
在
PreparedStatement
,
CallableStatement
,
及
ResultSet
接口中增加了一些
setter
和
updater
方法以支持
NCS
轉化
.
比如方法
setNString
,
setNCharacterStream
,
及
setNClob
等等
.
- 在 SQLInput and SQLOutput 接口中增加了讀寫方法以支持 t NClob 和 NString 對象 .
API
變化
JDBC 4.0
最大的變化來自于
API,
筆者在本小節對其做簡單介紹
.
Array
Array
接口增加了一個
free
方法來釋放
array
對象及其持有的資源
.
Connection
和
PooledConnection
Connection
接口現在提供一系列創建大對象的方法如
createClob
,
createBlob
等等
.
此外還有
getter
和
setter
對客戶端信息的重載方法
,
及驗證當前連接正確性的方法
.
PooledConnection
接口當前提供
addStatementEventListener
和
removeStatementEventListener
兩個方法來注冊和注銷
StatementEventListener
接口
,
這個接口是在本版
JDBC
中新引入的
.
這個接口的一個實例將獲取到
S
tatement
池中
PreparedStatement
s
的變化
.
比如,在注冊以后
,
當驅動調用
statementClosed
方法時,所有
StatementEventListener
將獲得
statement
已關閉的通知
.
DatabaseMetaData
不同的關系數據庫往往支持不同的特性
,
并通過不同的方法來實現這些特性
,
并可能會是用不同的數據類型
.
這將會導致移植性的問題,因為根據實現的不同,無法保證代碼在所有關系數據庫上都能正確執行
.
這樣的問題在一定程度上可以通過這個接口所獲得的信息來解決
.
比如,如果您在寫一個通過傳入
SQL
語句來建立表的代碼
.
您可能想知道在
CREATE TABLE
語句中有哪些數據類型是可用的,此時可以調用該接口中的
getTypeInfo
方法
.
本版
JDBC
增加了一些獲取信息的方法
.
在
Example4
中
,
我將通過一段代碼展示如何獲得滿足某種模式的數據庫結構的列表。
.
con = ds.getConnection();
DatabaseMetaData dmd = con.getMetaData();
rs=dmd.getSchemas("TABLE_CAT", "SYS%");
//iterate over the rs and print to console
首先通過調用
dmd.getCatalogs
并遍歷結果集
,
得到了唯一的一個值:
TABLE_CAT
.
接著通過調用
rs=dmd.getSchemas("TABLE_CAT", "SYS%")
得到以
SYS
開頭的數據庫和表結構
.
以下是筆者得到的結果
:
SYS
SYSCAT
SYSCS_DIAG
SYSCS_UTIL
SYSFUN
SYSIBM
SYSPROC
SYSSTAT
Scalar
函數支持
一個
scalar
函數操作預定義的輸入數據集合并返回結果
.
比如:
scalar
函數調用
ABS(number)
返回
number
的絕對值
.
這些
scalar
函數可以作為
SQL
字符串的一部分來使用
.
本版
JDBC
要求當所依賴的關系數據庫支持以下功能時:
CHAR_LENGTH
,
CHARACTER_LENGTH
,
CURRENT_DATE
,
CURRENT_TIME
,
CURRENT_TIMESTAMP
,
EXTRACT
,
OCTET_LENGTH
,
和
POSITION
,驅動必須實現這些功能。
Statement
,
PreparedStatement
,
和
CallableStatement
Statement
接口當前提供
isClosed
方法來判斷
statement
是否已關閉
,
setPoolable
用來設置是否可以被池化
,
用
isPoolable
來檢測當前的池化狀態。
PreparedStatement
及
CallableStatement
接口現在提供了更多插入大對象的方法
,
通過使用
InputStream
及
Reader
等
.
Wrapper
這個版本的
API
增加了一個新的
Wrapper
接口,
來提供一種訪問資源的實例的方法
,
這可能是基于架構的考慮
. Wrapper
模式
,
被許多的
JDBC
驅動實現應用以提供
JDBC API
之外的依賴于具體數據源的應用
.
這個接口的主要目的是用來提供供應商相關的功能。您可以通過調用
unwrap
方法來獲取到數據庫連接的接口實現的實例
.
因為這是一個重量級的操作
,
在使用前,應該先調用
isWrapperFor
方法來檢測是否當前實例是某種實現的一個間接或直接的
Wapper
能夠給出一個程序例子當然是最好的,但是
Apache Derby
參考手冊
l
指出
: "JDBC 4.0
引入了
wrapped JDBC
對象的概念
...
對于
Derby
來說
,
這對
Derby
來說是沒有意義的,因為
Derby
并不做規范之外的擴展
."
因此看來這種嘗試也就變得無甚必要了
!
結論
我們已經分為
4
類討論了
JDBC 4.0
所做的一些改進和新的特性,這些新特性增加了編程易用性,提高了生產率
.
盡管
API
規范已經推出幾個月了
,
到筆者截稿時,主流的數據庫廠商都沒有提供本版的
JDBC
驅動
.
當更多的供應商開始支持
JDBC 4.0
時
—
當然也包括您所中意的那個
—
您就可以享受
JDBC4.0
所提供的這些易用的功能了
.
最后,我認為有一個各大數據庫廠商的支持的
JDBC
版本的列表是必要的
. Sun Developer Network (SDN)
上有一個
JDBC Data Access API
(
http://developers.sun.com/product/jdbc/drivers
)
頁提供了一份更新不太及時的列表
.
原作者信息:
Sharad Acharya has more than eight years of experience in the software engineering field in multiple business domains including supply chain, insurance, banking, and mortgage.
@2008 楊一. 版權所有. 保留所有權利
posted on 2007-04-24 16:25 楊一 閱讀(3386) 評論(2) 編輯 收藏 所屬分類: Java EE