Java SE 6中的JDBC 4.0增強

來源:互聯網
上載者:User
  Java Platform, Standard Edition(Java SE)版本6(代碼名稱Mustang)現在已經推出了第二個beta版本,並計劃於今年十月份交付使用。Java SE 6包括幾處對Java Database Connectivity (JDBC)API
的增強。這些增強將被發布為JDBC 4.0版本。新JDBC功能的主要目標是提供更為簡單的設計方式和更好的開發人員體驗。本文概要說明了JDBC
4.0增強,以及它們給企業Java開發人員帶來的好處。我們將藉助一個使用Apache
Derby作為後端資料庫而構建的貸款處理應用程式範例,對新的JDBC功能進行探討。

Java SE 6.0

  Java SE 6.0版本的主要目標是提供相容性、穩定性和高品質。這個版本中有幾處有趣的增強,尤其是在監控與管理(JMX)、Web service、指令碼語言支援(使用Rhino指令碼引擎JSR 223將JavaScript技術與Java原始碼整合在一起)、資料庫連接性、注釋支援和安全性方面。JDBC API中還增加了幾個新功能,從新的RowId支援到更多的SQLException子類。

JDBC 4.0功能

  藉助Mustang中包含的Java SE Service Provider機制,Java開發人員不再需要使用像
Class.forName()這樣的代碼顯式地載入JDBC驅動程式,就能註冊JDBC驅動程式。通過在調用
DriverManager.getConnection()方法時自動定位合適的驅動程式,DriverManager類可以做到這一點。這個功能是向
後相容的,所以無需修改現有的JDBC代碼。

  
在訪問關聯式資料庫的Java應用程式中,通過最小化我們需要編寫的“模板”代碼,JDBC 4.0還改善了開發人員體驗。它還提供公用程式類,以改進JDBC驅動程式的註冊和卸載機制,以及管理資料來源和連線物件。

  
藉助JDBC 4.0,Java開發人員現在可以使用Annotations指定SQL查詢,從而利用Java SE 5.0(Tiger)
版本中提供的中繼資料支援。基於注釋的SQL查詢允許在Java代碼中使用Annotation關鍵字指定SQL查詢字串。這樣,我們就不必在兩個不同文
件中查看JDBC代碼以及這些代碼中調用的資料庫查詢了。例如,如果有一個叫做getActiveLoans()的方法,用於擷取貸款處理資料庫中的當前
貸款,可以使用@Query(sql="SELECT * FROM LoanApplicationDetails WHERE
LoanStatus = 'A'")注釋來修飾它。

  
此外,Java SE 6開發套件(JDK 6)的最後版本——與運行時環境(JRE 6)相反——將會有一個基於與它綁定在一起的Apache Derby的資料庫。這將協助開發人員理解新的JDBC功能,而不必單獨下載、安裝和設定資料庫產品。

  
JDBC 4.0中加入的主要功能包括:

  • 自動載入JDBC驅動程式類。
  • 串連管理增強。
  • 支援RowId SQL 類型。
  • 使用Annotations的DataSet SQL實現。
  • 處理增強SQL異常。
  • 支援SQL XML。

  還存在其他功能,比如對大對象(BLOB/CLOB)的改進支援和National Character Set Support。接下來的內容將會詳細分析這些功能。

自動載入JDBC驅動程式

  在JDBC
4.0中,調用getConnection方法時,不再需要使用Class.forName()顯式地載入JDBC驅動程式,因為
DriverManager將會試著從初始化時載入的以及使用與當前應用程式相同的類載入器明確式載入的JDBC驅動程式中,找出合適的驅動程式來。

 
  DriverManager方法getConnection和getDrivers已經增強為支援Java SE Service
Provider機制(SPM)。根據SPM,服務被定義為一組眾所周知的介面和抽象類別,而服務提供者則是服務的特定實現。它還指定在META-
INF/services目錄中儲存服務提供者設定檔。JDBC
4.0驅動程式必須包含檔案META-INF/services/java.sql.Driver。這個檔案包含JDBC驅動程式的
java.sql.Driver實現的名稱。例如,要載入JDBC驅動程式以串連到Apache
Derby資料庫,META-INF/services/java.sql.Driver檔案就要包含以下項:

  
org.apache.derby.jdbc.EmbeddedDriver

  
讓我們儘快瞭解如何使用這項新功能載入JDBC驅動程式管理器。下面的列表顯示了載入JDBC驅動程式通常使用的範例程式碼。我們假定需要串連到一個Apache Derby資料庫,因為我們在文章後面提到的應用程式範例中將使用這個資料庫:

 Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Connection conn

=DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword);

  但是在JDBC 4.0中,我們不需要Class.forName()這一行。我們只要調用getConnection()就可以獲得資料庫連接。

  
注意,這僅適用於在單機模式中獲得資料庫連接。如果使用某種資料庫連接池來管理串連,代碼將會有所區別。

串連管理

  在JDBC 4.0之前,我們依賴於JDBC URL來定義資料來源串連。現在有了JDBC
4.0,我們只要提供一組參數(比如主機名稱和連接埠號碼)給標準的串連工廠機制,就能獲得到任意資料來源的串連。Connection和Statement接
口中加入了新的方法,以便在管理池環境中的Statement對象時可以支援串連狀態跟蹤改進和更大的靈活性。中繼資料工具(JSR-175)
用於管理活動串連。我們還可以獲得中繼資料資訊,比如活動串連的狀態,還可以把串連指定為標準的(Connection,用於單機應用程式)、池化的
(PooledConnection)或者甚至是用於XA事務的分布式串連(XAConnection)。注意,我們沒有直接使用
XAConnection。它是由諸如WebLogic、WebSphere或JBoss這樣的Java EE應用伺服器內部的交易管理員來使用的。

RowId支援

  RowID介面被添加到JDBC
4.0中以支援ROWID資料類型,Oracle和DB2等資料庫也支援這種資料類型。當有多條記錄沒有惟一標識符列,而且需要在不允許複製的
Collection(比如Hashtable)中儲存查詢輸出時,RowId很有用。我們可以使用ResultSet的getRowId()方法來獲得
RowId,並使用PreparedStatement的setRowId()方法在查詢中使用RowId。

  
關於RowId對象要記住的一件重要事情是,分別在PreparedStatement和ResultSet中使用set或update方法
時,RowId對象的值無法在資料來源之間移植,可以認為它是特定於資料來源的。所以,禁止在不同的Connection和ResultSet對象之間共用
它。

  
DatabaseMetaData中的getRowIdLifetime()方法可用於確定RowId對象的生存期有效性。表1中列出了傳回值或行id可能取的值。

RowId 值 描述
ROWID_UNSUPPORTED 不支援ROWID資料類型。
ROWID_VALID_OTHER RowID的生存期依賴於資料庫廠商實現。
ROWID_VALID_TRANSACTION 只要在資料庫表中行未被刪除,RowID的生存期在當前的事務中。
ROWID_VALID_SESSION 只要在資料庫表中行未被刪除,RowID的生存期在當前會話的期間中。
ROWID_VALID_FOREVER 只要在資料庫表中行未被刪除,RowID的生存期是無限的。
基於注釋的SQL查詢

  JDBC 4.0規範利用注釋(Java SE 5中加入)允許開發人員把SQL查詢與Java類關聯在一起,同時不用編寫大量的代碼。此外,通過使用Generics(JSR 014)和中繼資料(JSR 175)API,
我們可以把SQL查詢與Java對象關聯在一起,從而指定查詢輸入和輸出參數。我們還可以把查詢結果綁定到Java類,以加速對查詢輸出的處理。我們無需
編寫通常用於把查詢結果填充到Java對象中的所有代碼。在Java代碼中指定SQL查詢時,有2種主要的注釋:Select和Update。

Select注釋

  Select注釋用於在Java類中指定選取查詢,以便使用get方法從資料庫表中擷取資料。表2顯示了Select注釋的各種屬性以及它們的用法。

名稱 類型 描述
sql String SQL Select查詢字串。
value String 與sql屬性相同。
tableName String 在其上調用sql的資料庫表的名稱。
readOnly、connected、 scrollable Boolean 標誌,分別用於指示返回的DataSet是唯讀還是可更新的,是否串連到後端資料庫,在connected模式中使用時是否可以滾動。
allColumnsMapped Boolean 標誌,用於指示sql注釋元素中的列名是否一對一地映射到DataSet中的欄位。

  下面是Select注釋的一個例子,用於從貸款資料庫獲得所有當前貸款:

interface LoanAppDetailsQuery extends BaseQuery {
@Select("SELECT * FROM LoanDetais where LoanStatus = 'A'")
DataSet<LoanApplication> getAllActiveLoans();
}

  sql注釋也支援I/O參數(參數標記由一個問號後面跟一個整數來表示)。下面是參數化sql查詢的一個例子:

interface LoanAppDetailsQuery extends BaseQuery {
@Select(sql="SELECT * from LoanDetails
where borrowerFirstName= 1 and borrowerLastName= 2")
DataSet<LoanApplication> getLoanDetailsByBorrowerName(String borrFirstName,
String borrLastName);
}
Update注釋

  Update注釋用於修飾Query介面方法,用於更新資料庫表中的一條或多條記錄。每個Update注釋都必須包含一個sql注釋類型的元素。下面是Update注釋的一個例子:

interface LoanAppDetailsQuery extends BaseQuery {
@Update(sql="update LoanDetails set LoanStatus = 1
where loanId = 2")
boolean updateLoanStatus(String loanStatus, int loanId);
}
處理增強SQL異常

  異常處理是Java編程的一個重要組成部分,特別是當串連到後端關聯式資料庫或在後端關聯式資料庫上執行查詢的時候。我們一直使用SQLException類來指示與資料庫相關的錯誤。JDBC 4.0在SQLException處理方面有幾處增強。下面是JDBC 4.0版本中的一些增強,在處理SQLExceptions時它們可以為開發人員帶來更好的體驗:

  • 新的SQLException子類
  • 支援因果關係
  • 支援增強for-each迴圈
新的SQLException類

  JDBC 4.0中建立了SQLException的新子類,以便為Java程式員提供一種編寫更多可移植錯誤處理代碼的手段。JDBC 4.0中引入了2類新的SQLException:

  • SQL非瞬時異常
  • SQL瞬時異常

  非瞬時異常:同一項操作重試失敗時拋出此異常,直到SQLException的原因得到糾正為止。表3顯示了JDBC 4.0中加入的新異常類,它們都是SQLNonTransientException的子類(SQLState類值定義在SQL 2003規範中。):

異常類 SQLState值
SQLFeatureNotSupportedException 0A
SQLNonTransientConnectionException 08
SQLDataException 22
SQLIntegrityConstraintViolationException 23
SQLInvalidAuthorizationException 28
SQLSyntaxErrorException 42

  瞬時異常:當操作在沒有任何應用程式級功能進行幹涉的情況下重試,前面失敗的JDBC操作能夠成功時拋出此異常。表4中列出了對SQLTransientException進行擴充的新異常。

異常類 SQLState值
SQLTransientConnectionException 08
SQLTransactionRollbackException 40
SQLTimeoutException None
因果關係

  現在,SQLException類支援配備有異常機制(也稱為Cause工具)的Java SE,這種機制讓我們能夠處理JDBC操作中拋出的多種異常(如果後端資料庫支援多異常功能)。這種情境發生在執行一條可能拋出多個SQLException的語句時。

  
我們可以使用SQLException中的getNextException()方法,通過異常鏈進行迭代。下面給出一些用於處理SQLException因果關係的範例程式碼:

catch(SQLException ex) {
while(ex != null) {
LOG.error("SQL State:" + ex.getSQLState());
LOG.error("Error Code:" + ex.getErrorCode());
LOG.error("Message:" + ex.getMessage());
Throwable t = ex.getCause();
while(t != null) {
LOG.error("Cause:" + t);
t = t.getCause();
}
ex = ex.getNextException();
}
}
增強For-Each迴圈

  SQLException類實現了Iterable介面,為Java SE
5中加入的for-each迴圈功能提供支援。迴圈的導航將遍曆SQLException及其原因。下面給出一個程式碼片段,對SQLException中
加入的for-each迴圈進行了說明。

catch(SQLException ex) {
for(Throwable e : ex ) {
LOG.error("Error occurred: " + e);
}
}
對國家字元集轉換的支援

  下面列出了處理國家字元集(National Character Set)時JDBC類中所做的增強:

  • JDBC資料類型:加入了新的JDBC資料類型,比如NCHAR、NVARCHAR、LONGNVARCHAR和NCLOB。
  • PreparedStatement:加入了新方法setNString、setNCharacterStream和setNClob。
  • CallableStatement:加入了新方法getNClob、getNString和getNCharacterStream。
  • ResultSet:介面加入了新方法updateNClob、updateNString和updateNCharacterStream。
對大對象(BLOB和CLOB)的增強支援

  下面列出了JDBC 4.0中對處理LOB所做的增強:

  • Connection:加入了新方法(createBlob()、createClob()和createNClob())以建立BLOB、CLOB和NCLOB對象的新執行個體。
  • PreparedStatement:加入了新方法setBlob()、setClob()和setNClob(),以便使用InputStream對象插入BLOB對象,以及使用Reader對象插入CLOB和NCLOB對象。
  • LOB:Blob、Clob和NClob介面中加入了新方法(free()),以便釋放這些對象佔用的資源。

  現在,讓我們看一看java.sql和javax.jdbc包中加入的一些新類,以及它們提供了哪些服務。

JDBC 4.0 API:新類RowId (java.sql)

  正如前面提過的那樣,這個介面代表著資料庫中的一個SQL ROWID值。ROWID是一個內建的SQL資料類型,用於識別資料庫表中的特定資料行。ROWID通常用在這樣的查詢中:該查詢從輸出行沒有惟一ID列的表中返回行。

 
 
CallableStatement、PreparedStatement和ResultSet介面中的方法,比如getRowId和setRowId,
允許程式員訪問SQL
ROWID值。介面還提供一個方法(叫做getBytes())把ROWID的值返回為位元組數組。DatabaseMetaData介面有一個叫做
getRowIdLifetime的新方法,可用於確定RowId對象的生存期。RowId的範圍可以是下列3種類型之一:

  • 在其中建立RowId的資料庫事務的期間。
  • 在其中建立RowId的會話的期間。
  • 資料庫表中的標識行,只要它尚未被刪除。
DataSet (java.sql)

  DataSet接
口為從執行SQL查詢返回的資料提供型別安全的視圖。DataSet可以在已串連或未串連模式中進行操作。當在已串連模式中使用時,其功能類似於
ResultSet。而在未串連模式中使用時,DataSet的功能則類似於CachedRowSet。因為DataSet擴充了List介面,我們可以
遍曆查詢返回的行。

  
現有的類中還加入了幾個新方法,比如Connection(createSQLXML、isValid)和ResultSet(getRowId)。

應用程式範例

  本文中使用的應用程式範例是一個貸款處理應用程式,它包含一個貸款尋找頁面,使用者可以在這個頁面上輸入一個貸款ID以獲得有關貸款的詳細資料,
然後提交表單。貸款尋找頁面調用一個控制器對象,而此控制器對象又調用DAO對象來訪問後端資料庫,從而獲得有關貸款的詳細資料。這些詳細資料包括借款人
姓名、貸款金額和貸款到期時間,它們均會顯示在一個貸款詳細資料頁面上。在後端資料庫中,我們使用一個叫做LoanApplicationDetails
的表來儲存貸款應用程式的詳細資料。

  
應用程式範例的用例是獲得特定貸款ID的貸款詳細資料。在註冊貸款並針對抵押產品和利率鎖定它之後,就可以獲得這些貸款詳細資料了。貸款處理應用程式的項目細節如表5所示。

名稱
Project Name JdbcApp
Project Directory c:/dev/projects/JdbcApp
DB Directory c:/dev/dbservers/apache/derby
JDK Directory c:/dev/java/jdk_1.6.0
IDE Directory c:/dev/tools/eclipse
Database Apache Derby 10.1.2.1
JDK 6.0 (beta 2 release)
IDE Eclipse 3.1
Unit Testing JUnit 4
Build Ant 1.6.5

  下表列出了串連貸款詳細資料Apache Derby資料庫時需要用到的JDBC參數。這些參數都儲存在一個叫做derby.properties的文字檔中,該檔案位於項目基目錄下的etc/jdbc目錄中(參見表6)。

名稱
JDBC Driver File LoanApp/META-INF/services/java.sql.driver
Driver org.apache.derby.ClientDriver
URL jdbc:derby:derbyDB
User Id user1
Password user1

  注意:Apache Derby資料庫提供2類JDBC驅動程式:Embedded
Driver(org.apache.derby.jdbc.EmbeddedDriver)和Client/Server
Driver(org.apache.derby.jdbc.ClientDriver)。在應用程式範例中我使用的是Client/Server
Driver版本。

  
下面給出用於啟動Derby資料庫伺服器和使用ij工具建立新資料庫的命令。

  
要啟動Derby Network Server,開啟一個命令提示,然後運行以下命令(修改DERBY_INSTALL和JAVA_HOME環境變數,從而影響本地環境)。

set DERBY_INSTALL=C:/dev/dbservers/db-derby-10.1.2.1-bin
set JAVA_HOME=C:/dev/java/jdk1.6.0
set DERBY_INSTALL=C:/dev/dbservers/db-derby-10.1.3.1-bin
set CLASSPATH=%CLASSPATH%;%DERBY_INSTALL%/lib/derby.jar;
%DERBY_INSTALL%/lib/derbytools.jar;
%DERBY_INSTALL%/lib/derbynet.jar;

cd %DERBY_INSTALL%/frameworks/ NetworkServer/bin
startNetworkServer.bat

  要串連到資料庫伺服器和建立測試資料庫,開啟另一個命令提示,然後運行以下命令。確保修改了DERBY_INSTALL和JAVA_HOME環境變數,以適應環境。

set JAVA_HOME=C:/dev/java/jdk1.6.0
set DERBY_INSTALL=C:/dev/dbservers/db-derby-10.1.3.1-bin
set CLASSPATH=%DERBY_INSTALL%/lib/derbyclient.jar;
%DERBY_INSTALL%/lib/derbytools.jar;.

%JAVA_HOME%/bin/java org.apache.derby.tools.ij
connect 'jdbc:derby://localhost:1527/LoanDB;create=true';
測試

  用於編譯Java原始碼的classpath設定應該包含位於項目主目錄下lib目錄中的derby.jarjunit4.jar檔案。我們還需要在classpath中包含etcetc/jdbcetc/log4j目錄,這樣應用程式就能訪問JDBC屬性和Log4J設定檔。我建立了一個Ant編譯指令碼(位於JdbcApp/build目錄中),以自動化編譯和打包Java代碼的任務。

  
用於測試貸款詳細資料Data Access Objects的測試類別叫做LoanAppDetailsDAOTest。我們傳入參數(比如貸款ID和借款人姓名)以獲得貸款詳細資料。

  
下面的內容給出了一些程式碼範例,這些代碼是關於JDBC 4.0規範的JDBC驅動程式自動載入和給予注釋的SQL查詢功能的。

自動載入JDBC驅動程式

  BaseDAO抽象類別有一個叫做getConnection的方法,用於獲得一個資料庫連接。下面的程式碼片段顯示了這個方法(注意,我們不必註冊JDBC驅動程式)。只要java.sql.Driver檔案中存在正確的驅動程式名稱(org.apache.derby.jdbc.ClientDriver),就可以自動載入JDBC驅動程式。

protected Connection getConnection() throws DAOException {
// Load JDBC properties first
if (jdbcUrl == null || jdbcUser == null ||
jdbcPassword == null) {
loadJdbcProperties();
}
// Get Connection
Connection conn = null;
try {
conn = DriverManager.getConnection(jdbcUrl, jdbcUser,
jdbcPassword);
} catch (SQLException sqle) {
throw new DAOException("Error in getting a DB connection.",
sqle);
}
return conn;
}
SQL注釋

  LoanAppDetailsQuery介面有帶有注釋的SQL查詢,用於獲得當前貸款(條件是loanstatus="A")的列表和基於貸
款人姓名的貸款詳細資料(在一個貸款人借貸多筆款項的情況下)。我們在本文的前面部分曾見過這些SQL注釋。下面給出的範例程式碼說明了如何調用使用
Annotation定義的SQL查詢。

public DataSet<LoanAppDetails> getAllActiveLoans() throws Exception {
// Get Connection
Connection conn = getConnection();
LoanAppDetailsQuery query = null;
DataSet<LoanAppDetails> loanDetails = null;
query = QueryObjectFactory.createQueryObject(
LoanAppDetailsQuery.class, conn);
loanDetails = query.getAllActiveLoans();
return loanDetails;
}
public DataSet<LoanAppDetails> getLoanDetailsByBorrowerName(
String borrFirstName, String borrLastName) throws Exception {
// Get Connection
Connection conn = getConnection();
LoanAppDetailsQuery query = null;
DataSet<LoanAppDetails> loanDetails = null;
query = QueryObjectFactory.createQueryObject(
LoanAppDetailsQuery.class, conn);
loanDetails = query.getLoanDetailsByBorrowerName(
borrFirstName,borrLastName);
return loanDetails;
}

結束語

  在使用SQL時,JDBC 4.0可以提供開發的簡便性並改善開發人員體驗。JDBC
4.0的另一個目標是提供企業級的JDBC功能,把API公開給涵蓋範圍更廣的工具集,以便更好地管理JDBC資源。此外,JDBC 4.0
API為JDBC驅動程式提供了一條遷移路徑,從而與J2EE
Connector架構(JCA)保持相容。這使得JDBC廠商能夠繼續實現JDBC技術Connector
API。當在企業級面向服務架構(Service Oriented
Architecture,SOA)應用程式中使用JDBC資料來源時,這一點很重要,因為在企業級SOA應用程式中,可以把JDBC資料來源部署為企業服務
匯流排(Enterprise Service Bus,ESB)架構中的另一個適配器,而不必為JDBC資料來源編寫ESB特定實現代碼。

  
在本文中,我們討論了JDBC 4.0中的增強,比如RowId支援、JDBC驅動程式載入和基於Annotations的SQL。JDBC 4.0中還將加入其他功能,以便在未來支援SQL 2003規範。要瞭解有關JDBC 4.0規範的更多資訊,請參考規範文檔。

參考資料
  • 應用程式範例代碼
  • Java SE 6首頁
  • Java SE 6參考實現(Mustang)Web網站
  • Java SE 6下載頁面
  • API規範
  • Apache Derby首頁
  • Tomcat 5.5首頁
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.