J2EE 開(kāi)發(fā)人員使用數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象(Data Access Object DAO)設(shè)計(jì)模式,以便將低級(jí)別的數(shù)據(jù)訪(fǎng)問(wèn)邏輯與高級(jí)別的業(yè)務(wù)邏輯分離。實(shí)現(xiàn) DAO 模式涉及比編寫(xiě)數(shù)據(jù)訪(fǎng)問(wèn)代碼更多的內(nèi)容。在本文中,Java 開(kāi)發(fā)人員 Sean C. Sullivan 討論了 DAO 編程中三個(gè)常常被忽略的方面:事務(wù)界定、異常處理和日志記錄。
在過(guò)去 18 個(gè)月中,我參加了一個(gè)由有才華的軟件工程師組成的小組,構(gòu)建定制的、基于 Web 的供應(yīng)鏈管理應(yīng)用程序。我們的應(yīng)用程序訪(fǎng)問(wèn)范圍廣泛的持久性數(shù)據(jù),包括配送狀態(tài)、供應(yīng)鏈衡量(metrics)、庫(kù)存、貨運(yùn)發(fā)票、項(xiàng)目管理數(shù)據(jù)和用戶(hù)信息。我們用 JDBC API 連接到我們公司的不同數(shù)據(jù)庫(kù)平臺(tái)上,并在整個(gè)應(yīng)用程序中使用 DAO 設(shè)計(jì)模式。
圖 1 顯示了應(yīng)用程序和數(shù)據(jù)源之間的關(guān)系:
圖 1. 應(yīng)用程序和數(shù)據(jù)源

在整個(gè)應(yīng)用程序中使用數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象(DAO)使我們可以將底層數(shù)據(jù)訪(fǎng)問(wèn)邏輯與業(yè)務(wù)邏輯分離開(kāi)來(lái)。我們構(gòu)建了為每一個(gè)數(shù)據(jù)源提供 GRUD (創(chuàng)建、讀取、更新、刪除)操作的 DAO 類(lèi)。
在本文中,我將為您介紹構(gòu)建更好的 DAO 類(lèi)的 DAO 實(shí)現(xiàn)策略和技術(shù)。更確切地說(shuō),我將討論日志、異常處理和事務(wù)界定。您將學(xué)到如何將這三者結(jié)合到自己的 DAO 類(lèi)中。本文假定您熟悉 JDBC API、SQL 和關(guān)系數(shù)據(jù)庫(kù)編程。
我們將以對(duì) DAO 設(shè)計(jì)模式和數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象的概述開(kāi)始。
DAO 基礎(chǔ)
DAO 模式是標(biāo)準(zhǔn) J2EE 設(shè)計(jì)模式之一。開(kāi)發(fā)人員用這種模式將底層數(shù)據(jù)訪(fǎng)問(wèn)操作與高層業(yè)務(wù)邏輯分離開(kāi)。一個(gè)典型的 DAO 實(shí)現(xiàn)有以下組件:
- 一個(gè) DAO 工廠(chǎng)類(lèi)
- 一個(gè) DAO 接口
- 一個(gè)實(shí)現(xiàn)了 DAO 接口的具體類(lèi)
- 數(shù)據(jù)傳輸對(duì)象(有時(shí)稱(chēng)為值對(duì)象)
具體的 DAO 類(lèi)包含訪(fǎng)問(wèn)特定數(shù)據(jù)源的數(shù)據(jù)的邏輯。在下面一節(jié)中您將學(xué)習(xí)設(shè)計(jì)和實(shí)現(xiàn)數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象的技術(shù)。有關(guān) DAO 設(shè)計(jì)模式的更多內(nèi)容請(qǐng)參閱 參考資料。
事務(wù)界定
關(guān)于 DAO 要記住的重要一點(diǎn)是它們是事務(wù)性對(duì)象。由 DAO 所執(zhí)行的每一個(gè)操作 -- 如創(chuàng)建、更新或者刪除數(shù)據(jù) -- 都與一個(gè)事務(wù)相關(guān)聯(lián)。因此,事務(wù)界定的概念就變得特別重要了。
事務(wù)界定是定義事務(wù)邊界的方式。J2EE 規(guī)范描述了兩種事務(wù)界定的模型:編程式(programmatic)和聲明式(declarative)。表 1 分析了這兩種模型:
表 1. 兩種事務(wù)界定的模型
聲明式事務(wù)界定 |
編程式事務(wù)界定 |
程序員用 EJB 部署描述符聲明事務(wù)屬性。 |
程序員負(fù)責(zé)編寫(xiě)事務(wù)邏輯。 |
運(yùn)行時(shí)環(huán)境(EJB 容器)用這些屬性自動(dòng)管理事務(wù)。 |
應(yīng)用程序通過(guò)一個(gè) API 控制事務(wù)。 |
我們將側(cè)重于編程式事務(wù)界定。
設(shè)計(jì)考慮
如前所述,DAO 是事務(wù)性對(duì)象。一個(gè)典型的 DAO 執(zhí)行像創(chuàng)建、更新和刪除這樣的事務(wù)性操作。在設(shè)計(jì) DAO 時(shí),首先要問(wèn)自己以下問(wèn)題:
- 事務(wù)要如何開(kāi)始?
- 事務(wù)應(yīng)如何結(jié)束?
- 哪一個(gè)對(duì)象將負(fù)責(zé)開(kāi)始一個(gè)事務(wù)?
- 哪一個(gè)對(duì)象將負(fù)責(zé)結(jié)束一個(gè)事務(wù)?
- DAO 是否要負(fù)責(zé)事務(wù)的開(kāi)始和結(jié)束?
- 應(yīng)用程序是否需要通過(guò)多個(gè) DAO 訪(fǎng)問(wèn)數(shù)據(jù)?
- 事務(wù)涉及到一個(gè) DAO 還是多個(gè) DAO?
- 一個(gè) DAO 是否調(diào)用另一個(gè) DAO 的方法?
了解上述問(wèn)題的答案將有助于您選擇最適合的 DAO 的事務(wù)界定策略。在 DAO 中有兩種主要的界定事務(wù)的策略。一種方式是讓 DAO 負(fù)責(zé)界定事務(wù),另一種將事務(wù)界定交給調(diào)用這個(gè) DAO 方法的對(duì)象處理。如果選擇了前一種方式,那么就將事務(wù)代碼嵌入到 DAO 中。如果選擇后一種方式,那么事務(wù)界定代碼就是在 DAO 類(lèi)外面。我們將使用簡(jiǎn)單的代碼示例幫助您更好理解每一種方式是如何工作的。
清單 1 顯示了一個(gè)有兩種數(shù)據(jù)操作的 DAO:創(chuàng)建和更新:
清單 1. DAO 方法
public void createWarehouseProfile(WHProfile profile);
public void updateWarehouseStatus(WHIdentifier id, StatusInfo status);
|
清單 2 顯示了一個(gè)簡(jiǎn)單的事務(wù)。事務(wù)界定在 DAO 類(lèi)外面。注意在這個(gè)例子中調(diào)用者是如何在一個(gè)事務(wù)中結(jié)合多個(gè) DAO 操作的。
清單 2. 調(diào)用者管理的事務(wù)
tx.begin(); // start the transaction
dao.createWarehouseProfile(profile);
dao.updateWarehouseStatus(id1, status1);
dao.updateWarehouseStatus(id2, status2);
tx.commit(); // end the transaction
|
這種事務(wù)界定策略對(duì)于需要在一個(gè)事務(wù)中訪(fǎng)問(wèn)多個(gè) DAO 的應(yīng)用程序特別有用。
可以用 JDBC API 或者 Java 事務(wù) API(Java Transaction API JTA)實(shí)現(xiàn)事務(wù)界定。 JDBC 事務(wù)界定比 JTA 事務(wù)界定要簡(jiǎn)單,但是 JTA 提供了更多的靈活性。在下面一節(jié)中我將更深入地分析事務(wù)界定的機(jī)制。
用 JDBC 進(jìn)行事務(wù)界定
JDBC 事務(wù)是用 Connection
對(duì)象控制的。JDBC Connection 接口(java.sql.Connection
)提供了兩種事務(wù)模式:自動(dòng)提交和手工提交。java.sql.Connection
提供了以下控制事務(wù)的方法:
public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
清單 3 顯示了如何用 JDBC API 界定一個(gè)事務(wù):
清單 3. 用 JDBC API 進(jìn)行事務(wù)界定
import java.sql.*;
import javax.sql.*;
// ...
DataSource ds = obtainDataSource();
Connection conn = ds.getConnection();
conn.setAutoCommit(false);
// ...
pstmt = conn.prepareStatement("UPDATE MOVIES ...");
pstmt.setString(1, "The Great Escape");
pstmt.executeUpdate();
// ...
conn.commit();
// ...
|
使用 JDBC 事務(wù)界定時(shí),您可以將多個(gè) SQL 語(yǔ)句結(jié)合到一個(gè)事務(wù)中。JDBC 事務(wù)的一個(gè)缺點(diǎn)是事務(wù)的范圍局限于一個(gè)數(shù)據(jù)庫(kù)連接。一個(gè) JDBC 事務(wù)不能跨越多個(gè)數(shù)據(jù)庫(kù)。在下面,我們將看一下如何用 JTA 進(jìn)行事務(wù)界定。因?yàn)?JTA 不像 JDBC 那樣有名,所以我們首先做一個(gè)簡(jiǎn)介。
JTA 簡(jiǎn)介
Java 事務(wù) API(JTA) 及其同門(mén)兄弟 Java 事務(wù)服務(wù)(Java Transaction Service JTS)為 J2EE 平臺(tái)提供了分布式事務(wù)服務(wù)。一個(gè)分布式的事務(wù)涉及一個(gè)事務(wù)管理器和一個(gè)或者多個(gè)資源管理器。一個(gè)資源管理器是任何類(lèi)型的持久性的數(shù)據(jù)存儲(chǔ)。事務(wù)管理器負(fù)責(zé)協(xié)調(diào)所有事務(wù)參與者之間的通信。事務(wù)管理器與資源管理器之間的關(guān)系如圖 2 所示:
圖 2. 一個(gè)事務(wù)管理器和資源管理器

JTA 事務(wù)比 JDBC 事務(wù)功能更強(qiáng)。JDBC 事務(wù)局限為一個(gè)數(shù)據(jù)庫(kù)連接,而 JTA 事務(wù)可以有多個(gè)參與者。所有下列 Java 平臺(tái)組件都可以參與 JTA 事務(wù):
- JDBC 連接
- JDO
PersistenceManager
對(duì)象
- JMS 隊(duì)列
- JMS 主題
- 企業(yè) JavaBeans
- 符合 J2EE 連接體系結(jié)構(gòu)(J2EE Connector Architecture)規(guī)范的資源適配器
使用 JTA 的事務(wù)界定
要用 JTA 進(jìn)行事務(wù)界定,應(yīng)用程序要調(diào)用 javax.transaction.UserTransaction
接口中的方法。清單 4 顯示了對(duì) UserTransaction
對(duì)象的典型 JNDI 查詢(xún):
清單 4. 一個(gè)對(duì) UserTransaction 對(duì)象的 JDNI 查詢(xún)
import javax.transaction.*;
import javax.naming.*;
// ...
InitialContext ctx = new InitialContext();
Object txObj = ctx.lookup("java:comp/UserTransaction");
UserTransaction utx = (UserTransaction) txObj;
|
當(dāng)應(yīng)用程序找到了 UserTransaction
對(duì)象后,就可以開(kāi)始事務(wù)了,如清單 5 所示:
清單 5. 用 JTA 開(kāi)始一個(gè)事務(wù)
utx.begin();
// ...
DataSource ds = obtainXADataSource();
Connection conn = ds.getConnection();
pstmt = conn.prepareStatement("UPDATE MOVIES ...");
pstmt.setString(1, "Spinal Tap");
pstmt.executeUpdate();
// ...
utx.commit();
// ...
|
當(dāng)應(yīng)用程序調(diào)用 commit()
時(shí),事務(wù)管理器用一個(gè)兩階段的提交協(xié)議結(jié)束事務(wù)。
控制事務(wù)的 JTA 方法
javax.transaction.UserTransaction
接口提供了以下事務(wù)控制方法:
public void begin()
public void commit()
public void rollback()
public int getStatus()
public void setRollbackOnly()
public void setTransactionTimeout(int)
應(yīng)用程序調(diào)用 begin()
開(kāi)始事務(wù)。應(yīng)用程序調(diào)用 commit()
或者 rollback()
結(jié)束事務(wù)。參閱參考資料以了解更多關(guān)于用 JTA 進(jìn)行事務(wù)管理的內(nèi)容。
使用 JTA 和 JDBC
開(kāi)發(fā)人員通常在 DAO 類(lèi)中用 JDBC 進(jìn)行底層數(shù)據(jù)操作。如果計(jì)劃用 JTA 界定事務(wù),那么就需要有一個(gè)實(shí)現(xiàn) javax.sql.XADataSource
、javax.sql.XAConnection
和 javax.sql.XAResource
接口的 JDBC 驅(qū)動(dòng)程序。一個(gè)實(shí)現(xiàn)了這些接口的驅(qū)動(dòng)程序?qū)⒖梢詤⑴c JTA 事務(wù)。一個(gè) XADataSource
對(duì)象就是一個(gè) XAConnection
對(duì)象的工廠(chǎng)。XAConnection
s 是參與 JTA 事務(wù)的 JDBC 連接。
您將需要用應(yīng)用服務(wù)器的管理工具設(shè)置 XADataSource
。從應(yīng)用服務(wù)器和 JDBC 驅(qū)動(dòng)程序的文檔中可以了解到相關(guān)的指導(dǎo)。
J2EE 應(yīng)用程序用 JNDI 查詢(xún)數(shù)據(jù)源。一旦應(yīng)用程序找到了數(shù)據(jù)源對(duì)象,它就調(diào)用 javax.sql.DataSource.getConnection()
以獲得到數(shù)據(jù)庫(kù)的連接。
XA 連接與非 XA 連接不同。一定要記住 XA 連接參與了 JTA 事務(wù)。這意味著 XA 連接不支持 JDBC 的自動(dòng)提交功能。同時(shí),應(yīng)用程序一定不要對(duì) XA 連接調(diào)用 java.sql.Connection.commit()
或者 java.sql.Connection.rollback()
。相反,應(yīng)用程序應(yīng)該使用 UserTransaction.begin()、
UserTransaction.commit()
和 serTransaction.rollback()
。
選擇最好的方式
我們討論了如何用 JDBC 和 JTA 界定事務(wù)。每一種方式都有其優(yōu)點(diǎn),您需要決定哪一種最適合于您的應(yīng)用程序。
在最近的許多項(xiàng)目中,我們小組是用 JDBC API 進(jìn)事務(wù)界定來(lái)構(gòu)建 DAO 類(lèi)的。這些 DAO 類(lèi)可以總結(jié)如下:
- 事務(wù)界定代碼嵌入在 DAO 類(lèi)中。
- DAO 類(lèi)使用 JDBC API 進(jìn)行事務(wù)界定。
- 調(diào)用者不能界定事務(wù)。
- 事務(wù)范圍局限于單個(gè) JDBC 連接。
JDBC 事務(wù)并不總是適合復(fù)雜的企業(yè)應(yīng)用程序。如果您的事務(wù)要跨越多個(gè) DAO 或者多個(gè)數(shù)據(jù)庫(kù),那么下列實(shí)現(xiàn)策略也許更合適:
- 事務(wù)用 JTA 界定。
- 事務(wù)界定代碼從 DAO 中分離出來(lái)。
- 調(diào)用者負(fù)責(zé)界定事務(wù)。
- DAO 加入一個(gè)全局事務(wù)。
JDBC 方式由于其簡(jiǎn)單性而具有吸引力,JTA 方式提供了更大的靈活性。您所選擇的實(shí)現(xiàn)將取決于應(yīng)用程序的特定需求。
日志記錄和 DAO
一個(gè)良好實(shí)現(xiàn)的 DAO 類(lèi)將使用日志記錄來(lái)捕捉有關(guān)其運(yùn)行時(shí)行為的細(xì)節(jié)。您可以選擇記錄異常、配置信息、連接狀態(tài)、JDBC 驅(qū)動(dòng)程序元數(shù)據(jù)、或者查詢(xún)參數(shù)。日志對(duì)于開(kāi)發(fā)的所有階段都很有用。我經(jīng)常在開(kāi)發(fā)時(shí)、測(cè)試時(shí)和生產(chǎn)中分析應(yīng)用程序日志。
在本節(jié),我將展示一個(gè)顯示如何將 Jakarta Commons Logging 加入到 DAO 中的代碼示例。在這之前,讓我們回顧一下一些基本知識(shí)。
選擇日志庫(kù)
許多開(kāi)發(fā)人員使用一種原始格式進(jìn)行日志記錄:System.out.println
和 System.err.println
。Println
語(yǔ)句速度快且使用方便,但是它們沒(méi)有提供全功能的日志記錄系統(tǒng)所具有的功能。表 2 列出了 Java 平臺(tái)的日志庫(kù):
表 2. Java 平臺(tái)的日志庫(kù)
日志庫(kù) |
開(kāi)放源代碼? |
URL |
java.util.logging |
不是 |
http://java.sun.com/j2se/ |
Jakarta Log4j |
是 |
http://jakarta.apache.org/log4j/ |
Jakarta Commons Logging |
是 |
http://jakarta.apache.org/commons/logging.html |
java.util.logging
是 J2SE 1.4 平臺(tái)上的標(biāo)準(zhǔn) API。不過(guò),大多數(shù)開(kāi)發(fā)人員同意 Jakarta Log4j 提供了更多的功能和更大的靈活性。Log4j 優(yōu)于 java.util.logging 的一點(diǎn)是它同時(shí)支持 J2SE 1.3 和 J2SE 1.4 平臺(tái)。
Jakarta Commons Logging 可以與 java.util.logging
或者 Jakarta Log4j 一同使用。Commons Logging 是一個(gè)日志抽象層,它隔離了應(yīng)用程序與底層日志實(shí)現(xiàn)。使用 Commons Logging,您可以通過(guò)改變配置文件更換底層日志實(shí)現(xiàn)。Commons Logging 在 Jakarta Struts 1.1 和 Jakarta HttpClient 2.0 中使用。
一個(gè)日志記錄示例
清單 7 顯示了如何在 DAO 類(lèi)中使用 Jakarta Commons Logging:
清單 7. DAO 類(lèi)中的 Jakarta Commons Logging
import org.apache.commons.logging.*;
class DocumentDAOImpl implements DocumentDAO
{
static private final Log log = LogFactory.getLog(DocumentDAOImpl.class);
public void deleteDocument(String id)
{
// ...
log.debug("deleting document: " + id);
// ...
try
{
// ... data operations ...
}
catch (SomeException ex)
{
log.error("Unable to delete document", ex);
// ... handle the exception ...
}
}
}
|
日志記錄是所有任務(wù)關(guān)鍵型應(yīng)用程序的重要部分。如果在 DAO 中遇到故障,那么日志通常可以提供判斷出錯(cuò)位置的最好信息。將日志加入到 DAO 可以保證您有機(jī)會(huì)進(jìn)行調(diào)試和故障排除。
DAO 中的異常處理
我們討論過(guò)了事務(wù)界定和日志,現(xiàn)在對(duì)于如何在數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象上應(yīng)用它們有了更深入的理解。我們的第三個(gè)和最后一個(gè)討論議題是異常處理。遵從幾個(gè)簡(jiǎn)單的異常處理指導(dǎo)可以使您的 DAO 更容易使用、更健壯及更易于維護(hù)。
在實(shí)現(xiàn) DAO 模式時(shí),考慮以下問(wèn)題:
- DAO 的公共接口中的方法是否拋出檢查過(guò)的異常?
- 如果是的話(huà),拋出何種檢查過(guò)的異常?
- 在 DAO 實(shí)現(xiàn)類(lèi)中如何處理異常?
在使用 DAO 模式的過(guò)程中,我們的小組開(kāi)發(fā)了一些處理異常的原則。遵從這些原則可以極大地改進(jìn)您的 DAO:
- DAO 方法應(yīng)該拋出有意義的異常。
- DAO 方法不應(yīng)該拋出
java.lang.Exception
。java.lang.Exception
太一般化了。它不傳遞關(guān)于底層問(wèn)題的任何信息。
- DAO 方法不應(yīng)該拋出
java.sql.SQLException
。SQLException 是一個(gè)低級(jí)別的 JDBC 異常。一個(gè) DAO 應(yīng)該力爭(zhēng)封裝 JDBC 而不是將 JDBC 公開(kāi)給應(yīng)用程序的其余部分。
- 只有在可以合理地預(yù)期調(diào)用者可以處理異常時(shí),DAO 接口中的方法才應(yīng)該拋出檢查過(guò)的異常。如果調(diào)用者不能以有意義的方式處理這個(gè)異常,那么考慮拋出一個(gè)未檢查的(運(yùn)行時(shí))異常。
- 如果數(shù)據(jù)訪(fǎng)問(wèn)代碼捕獲了一個(gè)異常,不要忽略它。忽略捕獲的異常的 DAO 是很難進(jìn)行故障診斷的。
- 使用鏈接的異常將低級(jí)別的異常轉(zhuǎn)化為高級(jí)別的異常。
- 考慮定義標(biāo)準(zhǔn) DAO 異常類(lèi)。Spring Framework (參閱參考資料)提供了很好的一套預(yù)定義的 DAO 異常類(lèi)。
有關(guān)異常和異常處理技術(shù)的更多信息參閱參考資料。
實(shí)現(xiàn)實(shí)例: MovieDAO
MovieDAO
是一個(gè)展示本文中討論的所有技術(shù)的 DAO:事務(wù)界定、日志和異常處理。您可以在參考資料一節(jié)中找到 MovieDAO
源代碼。代碼分為三個(gè)包:
daoexamples.exception
daoexamples.movie
daoexamples.moviedemo
DAO 模式的這個(gè)實(shí)現(xiàn)包含下面列出的類(lèi)和接口:
daoexamples.movie.MovieDAOFactory
daoexamples.movie.MovieDAO
daoexamples.movie.MovieDAOImpl
daoexamples.movie.MovieDAOImplJTA
daoexamples.movie.Movie
daoexamples.movie.MovieImpl
daoexamples.movie.MovieNotFoundException
daoexamples.movie.MovieUtil
MovieDAO
接口定義了 DAO 的數(shù)據(jù)操作。這個(gè)接口有五個(gè)方法,如下所示:
public Movie findMovieById(String id)
public java.util.Collection findMoviesByYear(String year)
public void deleteMovie(String id)
public Movie createMovie(String rating, String year, String, title)
public void updateMovie(String id, String rating, String year, String title)
daoexamples.movie
包包含 MovieDAO
接口的兩個(gè)實(shí)現(xiàn)。每一個(gè)實(shí)現(xiàn)使用一種不同的方式進(jìn)行事務(wù)界定,如表 3 所示:
表 3. MovieDAO 實(shí)現(xiàn)
|
MovieDAOImpl |
MovieDAOImplJTA |
實(shí)現(xiàn) MovieDAO 接口? |
是 |
是 |
通過(guò) JNDI 獲得 DataSource? |
是 |
是 |
從 DataSource 獲得 java.sql.Connection 對(duì)象? |
是 |
是 |
DAO 在內(nèi)部界定事務(wù)? |
是 |
否 |
使用 JDBC 事務(wù)? |
是 |
否 |
使用一個(gè) XA DataSource? |
否 |
是 |
參與 JTA 事務(wù)? |
否 |
是 |
MovieDAO 演示應(yīng)用程序
這個(gè)演示應(yīng)用程序是一個(gè)名為 daoexamples.moviedemo.DemoServlet
的 servlet 類(lèi)。DemoServlet
使用這兩個(gè) Movie DAO 查詢(xún)和更新表中的電影數(shù)據(jù)。
這個(gè) servlet 展示了如何將支持 JTA 的 MovieDAO
和 Java 消息服務(wù)(Java Message Service)結(jié)合到一個(gè)事務(wù)中,如清單 8 所示。
清單 8. 將 MovieDAO 和 JMS 代碼結(jié)合到一個(gè)事務(wù)中
UserTransaction utx = MovieUtil.getUserTransaction();
utx.begin();
batman = dao.createMovie("R",
"2008",
"Batman Reloaded");
publisher = new MessagePublisher();
publisher.publishTextMessage("I'll be back");
dao.updateMovie(topgun.getId(),
"PG-13",
topgun.getReleaseYear(),
topgun.getTitle());
dao.deleteMovie(legallyblonde.getId());
utx.commit();
|
要運(yùn)行這個(gè)演示應(yīng)用程序,需要在應(yīng)用服務(wù)器上配置一個(gè) XA 數(shù)據(jù)源和一個(gè)非 XA 數(shù)據(jù)源。然后,部署 daoexamples.ear 文件。這個(gè)應(yīng)用程序可以在任何兼容 J2EE 1.3 的應(yīng)用服務(wù)器上運(yùn)行。參閱參考資料以獲得 EAR 文件和源代碼。
結(jié)束語(yǔ)
正如本文所展示的,實(shí)現(xiàn) DAO 模式需要做比編寫(xiě)低級(jí)別的數(shù)據(jù)訪(fǎng)問(wèn)代碼更多的工作。現(xiàn)在,通過(guò)選擇一個(gè)適合您的應(yīng)用程序的事務(wù)界定策略、通過(guò)在 DAO 類(lèi)中加入日志記錄,以及通過(guò)遵從幾項(xiàng)簡(jiǎn)單的異常處理原則,您可以構(gòu)建更好的 DAO。