1. 程式人生 > >J2EE設計模式-Dao(Data Access Object)模式

J2EE設計模式-Dao(Data Access Object)模式

在過去 18 個月中,我參加了一個由有才華的軟體工程師組成的小組,構建定製的、基於 Web 的供應鏈管理應用程式。我們的應用程式訪問範圍廣泛的永續性資料,包括配送狀態、供應鏈衡量(metrics)、庫存、貨運發票、專案管理資料和使用者資訊。我們用 JDBC API 連線到我們公司的不同資料庫平臺上,並在整個應用程式中使用 DAO 設計模式。

圖 1 顯示了應用程式和資料來源之間的關係:

圖 1. 應用程式和資料來源
應用程式和資料來源

在整個應用程式中使用資料訪問物件(DAO)使我們可以將底層資料訪問邏輯與業務邏輯分離開來。我們構建了為每一個數據源提供 GRUD (建立、讀取、更新、刪除)操作的 DAO 類。

在本文中,我將為您介紹構建更好的 DAO 類的 DAO 實現策略和技術。更確切地說,我將討論日誌、異常處理和事務界定。您將學到如何將這三者結合到自己的 DAO 類中。本文假定您熟悉 JDBC API、SQL 和關係資料庫程式設計。

我們將以對 DAO 設計模式和資料訪問物件的概述開始。

DAO基礎

DAO 模式是標準 J2EE 設計模式之一。開發人員用這種模式將底層資料訪問操作與高層業務邏輯分離開。一個典型的 DAO 實現有以下元件:

  • 一個 DAO 工廠類
  • 一個 DAO 介面
  • 一個實現了 DAO 介面的具體類
  • 資料傳輸物件(有時稱為值物件)

具體的 DAO 類包含訪問特定資料來源的資料的邏輯。在下面一節中您將學習設計和實現資料訪問物件的技術。有關 DAO 設計模式的更多內容請參閱 

參考資料

事務界定

關於 DAO 要記住的重要一點是它們是事務性物件。由 DAO 所執行的每一個操作 -- 如建立、更新或者刪除資料 -- 都與一個事務相關聯。因此, 事務界定的概念就變得特別重要了。

事務界定是定義事務邊界的方式。J2EE 規範描述了兩種事務界定的模型:程式設計式(programmatic)和宣告式(declarative)。表 1 分析了這兩種模型:

表 1. 兩種事務界定的模型
宣告式事務界定 程式設計式事務界定
程式設計師用 EJB 部署描述符宣告事務屬性。 程式設計師負責編寫事務邏輯。
執行時環境(EJB 容器)用這些屬性自動管理事務。 應用程式通過一個 API 控制事務。

我們將側重於程式設計式事務界定。

設計考慮

如前所述,DAO 是事務性物件。一個典型的 DAO 執行像建立、更新和刪除這樣的事務性操作。在設計 DAO 時,首先要問自己以下問題:

  • 事務要如何開始?
  • 事務應如何結束?
  • 哪一個物件將負責開始一個事務?
  • 哪一個物件將負責結束一個事務?
  • DAO 是否要負責事務的開始和結束?
  • 應用程式是否需要通過多個 DAO 訪問資料?
  • 事務涉及到一個 DAO 還是多個 DAO?
  • 一個 DAO 是否呼叫另一個 DAO 的方法?

瞭解上述問題的答案將有助於您選擇最適合的 DAO 的事務界定策略。在 DAO 中有兩種主要的界定事務的策略。一種方式是讓 DAO 負責界定事務,另一種將事務界定交給呼叫這個 DAO 方法的物件處理。如果選擇了前一種方式,那麼就將事務程式碼嵌入到 DAO 中。如果選擇後一種方式,那麼事務界定程式碼就是在 DAO 類外面。我們將使用簡單的程式碼示例幫助您更好理解每一種方式是如何工作的。

清單 1 顯示了一個有兩種資料操作的 DAO:建立和更新:

清單 1. DAO 方法
       public void createWarehouseProfile(WHProfile profile);
       public void updateWarehouseStatus(WHIdentifier id, StatusInfo status);

清單 2 顯示了一個簡單的事務。事務界定在 DAO 類外面。注意在這個例子中呼叫者是如何在一個事務中結合多個 DAO 操作的。

清單 2. 呼叫者管理的事務
      tx.begin();    // start the transaction
      dao.createWarehouseProfile(profile);
      dao.updateWarehouseStatus(id1, status1);
      dao.updateWarehouseStatus(id2, status2);
      tx.commit();   // end the transaction

這種事務界定策略對於需要在一個事務中訪問多個 DAO 的應用程式特別有用。

可以用 JDBC API 或者 Java 事務 API(Java Transaction API JTA)實現事務界定。 JDBC 事務界定比 JTA 事務界定要簡單,但是 JTA 提供了更多的靈活性。在下面一節中我將更深入地分析事務界定的機制。

用 JDBC 進行事務界定

JDBC 事務是用 Connection 物件控制的。JDBC Connection 介面( java.sql.Connection )提供了兩種事務模式:自動提交和手工提交。java.sql.Connection 提供了以下控制事務的方法:

  • public void setAutoCommit(boolean)
  • public boolean getAutoCommit()
  • public void commit()
  • public void rollback()

清單 3 顯示瞭如何用 JDBC API 界定一個事務:

清單 3. 用 JDBC API 進行事務界定
      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 事務界定時,您可以將多個 SQL 語句結合到一個事務中。JDBC 事務的一個缺點是事務的範圍侷限於一個數據庫連線。一個 JDBC 事務不能跨越多個數據庫。在下面,我們將看一下如何用 JTA 進行事務界定。因為 JTA 不像 JDBC 那樣有名,所以我們首先做一個簡介。

JTA簡介

Java 事務 API(JTA) 及其同門兄弟 Java 事務服務(Java Transaction Service JTS)為 J2EE 平臺提供了分散式事務服務。一個 分散式的事務涉及一個事務管理器和一個或者多個資源管理器。一個 資源管理器是任何型別的永續性的資料儲存。事務管理器負責協調所有事務參與者之間的通訊。事務管理器與資源管理器之間的關係如圖 2 所示:

圖 2. 一個事務管理器和資源管理器
一個事務管理器和資源管理器

JTA 事務比 JDBC 事務功能更強。JDBC 事務侷限為一個數據庫連線,而 JTA 事務可以有多個參與者。所有下列 Java 平臺元件都可以參與 JTA 事務:

  • JDBC 連線
  • JDO PersistenceManager 物件
  • JMS 佇列
  • JMS 主題
  • 企業 JavaBeans
  • 符合 J2EE 連線體系結構(J2EE Connector Architecture)規範的資源介面卡

使用 JTA 的事務界定

要用 JTA 進行事務界定,應用程式要呼叫 javax.transaction.UserTransaction 介面中的方法。清單 4 顯示了對 UserTransaction 物件的典型 JNDI 查詢:

清單 4. 一個對 UserTransaction 物件的 JDNI 查詢
      import javax.transaction.*;
      import javax.naming.*;
      // ...
      InitialContext ctx = new InitialContext();
      Object txObj = ctx.lookup("java:comp/UserTransaction");
      UserTransaction utx = (UserTransaction) txObj;

當應用程式找到了 UserTransaction 物件後,就可以開始事務了,如清單 5 所示:

清單 5. 用 JTA 開始一個事務
      utx.begin();
      // ...
      DataSource ds = obtainXADataSource();
      Connection conn = ds.getConnection();
      pstmt = conn.prepareStatement("UPDATE MOVIES ...");
      pstmt.setString(1, "Spinal Tap");
      pstmt.executeUpdate();
      // ...
      utx.commit();
      // ...

當應用程式呼叫 commit() 時,事務管理器用一個兩階段的提交協議結束事務。

控制事務的 JTA 方法

javax.transaction.UserTransaction 介面提供了以下事務控制方法:

  • public void begin()
  • public void commit()
  • public void rollback()
  • public int getStatus()
  • public void setRollbackOnly()
  • public void setTransactionTimeout(int)

應用程式呼叫 begin() 開始事務。應用程式呼叫 commit() 或者 rollback() 結束事務。參閱 參考資料以瞭解更多關於用 JTA 進行事務管理的內容。

使用 JTA 和 JDBC

開發人員通常在 DAO 類中用 JDBC 進行底層資料操作。如果計劃用 JTA 界定事務,那麼就需要有一個實現 javax.sql.XADataSource 、javax.sql.XAConnection 和 javax.sql.XAResource 介面的 JDBC 驅動程式。一個實現了這些介面的驅動程式將可以參與 JTA 事務。一個XADataSource 物件就是一個 XAConnection 物件的工廠。 XAConnection s 是參與 JTA 事務的 JDBC 連線。

您將需要用應用伺服器的管理工具設定 XADataSource 。從應用伺服器和 JDBC 驅動程式的文件中可以瞭解到相關的指導。

J2EE 應用程式用 JNDI 查詢資料來源。一旦應用程式找到了資料來源物件,它就呼叫 javax.sql.DataSource.getConnection() 以獲得到資料庫的連線。

XA 連線與非 XA 連線不同。一定要記住 XA 連線參與了 JTA 事務。這意味著 XA 連線不支援 JDBC 的自動提交功能。同時,應用程式一定不要對 XA 連線呼叫 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() 。相反,應用程式應該使用UserTransaction.begin()、UserTransaction.commit() 和 serTransaction.rollback() 。

選擇最好的方式

我們討論瞭如何用 JDBC 和 JTA 界定事務。每一種方式都有其優點,您需要決定哪一種最適合於您的應用程式。

在最近的許多專案中,我們小組是用 JDBC API 進事務界定來構建 DAO 類的。這些 DAO 類可以總結如下:

  • 事務界定程式碼嵌入在 DAO 類中。
  • DAO 類使用 JDBC API 進行事務界定。
  • 呼叫者不能界定事務。
  • 事務範圍侷限於單個 JDBC 連線。

JDBC 事務並不總是適合複雜的企業應用程式。如果您的事務要跨越多個 DAO 或者多個數據庫,那麼下列實現策略也許更合適:

  • 事務用 JTA 界定。
  • 事務界定程式碼從 DAO 中分離出來。
  • 呼叫者負責界定事務。
  • DAO 加入一個全域性事務。

JDBC 方式由於其簡單性而具有吸引力,JTA 方式提供了更大的靈活性。您所選擇的實現將取決於應用程式的特定需求。

日誌記錄和 DAO

一個良好實現的 DAO 類將使用日誌記錄來捕捉有關其執行時行為的細節。您可以選擇記錄異常、配置資訊、連線狀態、JDBC 驅動程式元資料、或者查詢引數。日誌對於開發的所有階段都很有用。我經常在開發時、測試時和生產中分析應用程式日誌。

在本節,我將展示一個顯示如何將 Jakarta Commons Logging 加入到 DAO 中的程式碼示例。在這之前,讓我們回顧一下一些基本知識。

選擇日誌庫

許多開發人員使用一種原始格式進行日誌記錄: System.out.println 和 System.err.println 。 Println 語句速度快且使用方便,但是它們沒有提供全功能的日誌記錄系統所具有的功能。表 2 列出了 Java 平臺的日誌庫:

表 2. Java 平臺的日誌庫
日誌庫 開放原始碼? 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

Jakarta Commons Logging 可以與 java.util.logging 或者 Jakarta Log4j 一同使用。Commons Logging 是一個日誌抽象層,它隔離了應用程式與底層日誌實現。使用 Commons Logging,您可以通過改變配置檔案更換底層日誌實現。Commons Logging 在 Jakarta Struts 1.1 和 Jakarta HttpClient 2.0 中使用。

一個日誌記錄示例

清單 7 顯示瞭如何在 DAO 類中使用 Jakarta Commons Logging:

清單 7. DAO 類中的 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 ...
	}
      }
}

日誌記錄是所有任務關鍵型應用程式的重要部分。如果在 DAO 中遇到故障,那麼日誌通常可以提供判斷出錯位置的最好資訊。將日誌加入到 DAO 可以保證您有機會進行除錯和故障排除。

DAO 中的異常處理

我們討論過了事務界定和日誌,現在對於如何在資料訪問物件上應用它們有了更深入的理解。我們的第三個和最後一個討論議題是異常處理。遵從幾個簡單的異常處理指導可以使您的 DAO 更容易使用、更健壯及更易於維護。

在實現 DAO 模式時,考慮以下問題:

  • DAO 的公共介面中的方法是否丟擲檢查過的異常?
  • 如果是的話,丟擲何種檢查過的異常?
  • 在 DAO 實現類中如何處理異常?

在使用 DAO 模式的過程中,我們的小組開發了一些處理異常的原則。遵從這些原則可以極大地改進您的 DAO:

  • DAO 方法應該丟擲有意義的異常。
  • DAO 方法不應該丟擲 java.lang.Exception 。 java.lang.Exception 太一般化了。它不傳遞關於底層問題的任何資訊。
  • DAO 方法不應該丟擲 java.sql.SQLException 。SQLException 是一個低級別的 JDBC 異常。一個 DAO 應該力爭封裝 JDBC 而不是將 JDBC 公開給應用程式的其餘部分。
  • 只有在可以合理地預期呼叫者可以處理異常時,DAO 介面中的方法才應該丟擲檢查過的異常。如果呼叫者不能以有意義的方式處理這個異常,那麼考慮丟擲一個未檢查的(執行時)異常。
  • 如果資料訪問程式碼捕獲了一個異常,不要忽略它。忽略捕獲的異常的 DAO 是很難進行故障診斷的。
  • 使用連結的異常將低級別的異常轉化為高級別的異常。
  • 考慮定義標準 DAO 異常類。Spring Framework (參閱 參考資料)提供了很好的一套預定義的 DAO 異常類。

有關異常和異常處理技術的更多資訊參閱 參考資料

實現例項: MovieDAO

MovieDAO 是一個展示本文中討論的所有技術的 DAO:事務界定、日誌和異常處理。您可以在 參考資料一節中找到 MovieDAO 原始碼。程式碼分為三個包:

  • daoexamples.exception
  • daoexamples.movie
  • daoexamples.moviedemo

DAO 模式的這個實現包含下面列出的類和介面:

  • 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 的資料操作。這個介面有五個方法,如下所示:

  • 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 介面的兩個實現。每一個實現使用一種不同的方式進行事務界定,如表 3 所示:

表 3. MovieDAO 實現
MovieDAOImpl MovieDAOImplJTA
實現 MovieDAO 介面?
通過 JNDI 獲得 DataSource?
從 DataSource 獲得 java.sql.Connection 物件?
DAO 在內部界定事務?
使用 JDBC 事務?
使用一個 XA DataSource?
參與 JTA 事務?

MovieDAO 演示應用程式

這個演示應用程式是一個名為 daoexamples.moviedemo.DemoServlet 的 servlet 類。 DemoServlet 使用這兩個 Movie DAO 查詢和更新表中的電影資料。

這個 servlet 展示瞭如何將支援 JTA 的 MovieDAO 和 Java 訊息服務(Java Message Service)結合到一個事務中,如清單 8 所示。

清單 8. 將 MovieDAO 和 JMS 程式碼結合到一個事務中

相關推薦

J2EE設計模式-DaoData Access Object模式

在過去 18 個月中,我參加了一個由有才華的軟體工程師組成的小組,構建定製的、基於 Web 的供應鏈管理應用程式。我們的應用程式訪問範圍廣泛的永續性資料,包括配送狀態、供應鏈衡量(metrics)、庫存、貨運發票、專案管理資料和使用者資訊。我們用 JDBC API 連線到我們公司的不同資料庫平臺上,並在整

設計模式之資料訪問物件模式Data Access Object Pattern

資料訪問物件模式(Data Access Object Pattern)或 DAO 模式用於把低階的資料訪問 API 或操作從高階的業務服務中分離出來。以下是資料訪問物件模式的參與者 資料訪問物件介面(Data Access Object Interface) - 該介面定義了在一個模型物件

Java DTOdata transfer object的使用

解耦介面呼叫者與介面實現者 在介面設計當中,如果涉及到同時返回多個關聯物件,如問題Question,又包括問題選項QuestionOptions,此時一般想到的做法是使用一個Map,然後將qustion和questionOption分別作為key,然後返回,這種做法使得呼叫者

c++ 設計模式9 Abstract Factory 抽象工廠模式

構建 數據庫 strac 無需 div exec oracl dfa tle 5.2 抽象工廠模式 動機:在軟件系統中,經常面臨著“一系列相互依賴的對象”的創建工作;同時,由於需求的變化,往往存在更多系列對象的創建工作。 代碼示例: 實現利用數據庫的業務邏輯,支持多數據

設計模式的征途—14.職責鏈Chain of Responsibility模式

and 問題 調試 決定 tor 客戶端 edi toa 發送 相信大家都玩過類似於“鬥地主”的紙牌遊戲,某人出牌給他的下家,下家看看手中的牌,如果要不起,則將出牌請求轉發給他的下家,其下家再進行判斷。一個循環下來,如果其他人都要不起該牌,則最初的出

設計模式 十七 狀態模式State物件行為型

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

設計模式 ( 十五 ) 觀察者模式Observer物件行為型

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

常用設計模式總結面試常問

Singleton(單例模式) 一句話總結:一個類在Java虛擬機器中只有一個物件,並提供一個全域性訪問點。 生活中例子:太陽、月亮、國家主席等。 解決什麼問題:物件的唯一性,效能浪費太多。 專案裡面怎麼用:資料庫連線物件,屬性配置檔案的讀取物件。 模式結構:分為餓漢式和懶漢式(

設計模式php示例 單例模式和工廠模式

所謂的設計模式,就是具有多年開發經驗的人,在實際工作中為了解決某一種需求,而形成的一套程式碼方案。 1.單例模式: 單例模式:所謂的單例模式就是單一的例項。通過一個類永遠只能獲取一個物件。 基本的實現思路:單例模式要求類能夠有返回物件一個引用(永遠是同一個)和一個獲得該例項的方法(必

《Java多執行緒程式設計實戰》——第3章 Immutable Object不可變物件模式

通過使用對外可見的狀態不可變的物件,無需額外的同步訪問控制。既保證了資料一致性,又避免了同步訪問控制所產生的額外開銷和問題,也簡化了程式設計。 狀態不可變的物件:物件一經建立,其對外可見的狀態就保持不變,如String和Integer。 Immutable Object模式:將現實世界中狀態

設計模式教程Design Patterns Tutorial筆記之一 建立型模式Creational Patterns

目錄 · 概述 · Factory     · What is the Factory Design Pattern?     · 

設計模式之單例模式懶漢式double check

上一篇文章中的懶漢式單例模式採用同步方法保證了執行緒安全,但是開銷很大,每次執行該方法都會檢查鎖。下面採用double check的方式進行改寫,下面這種實現看似可行,實則有缺陷,具體缺陷在後文分析: 注意上面第二幅圖中對lazyDoubleCheckSingl

設計模式總結Java語言實現

有人說,為什麼要學習設計模式,有些設計模式寫起來十分複雜,在平時程式設計時不會刻意去使用它。但是,設計模式是程式碼規範的一種體現,學號設計模式併合理應用,可以避免bug的出現,增強程式碼的魯棒性,便於後

頁面物件Page Object模式

內容轉載自 https://www.cnblogs.com/yytesting/p/6973474.html 頁面物件(Page Object)模式是目前自動化測試領域普遍使用的設計模式之一,此模式可以大大提高測試程式碼的複用率,提高測試指令碼的編寫效率和維護效率,是中級自動化測試工程師的必備技能之一。

【java設計模式】之 責任鏈chain of resposibility模式

  責任鏈模式,顧名思義,就是一條鏈。這個鏈到底是怎麼執行的呢?它主要是將能夠處理同一類請求的物件連成一條鏈,所提交的請求沿著鏈傳遞,鏈上的物件逐個判斷是否有能力處理該請求,如果能則處理,如果不能則

設計模式總結不斷完善中...

設計模式 簡單工廠模式 簡單工廠模式 oo思想: 某養豬大廠要求設計一個計算器,要求實現add、sub、mul、div,實際考察的是面向物件 的封裝、繼承和多型,那麼如何實現吶?封裝要做到業務層和檢視層分離,從控制檯接 收

設計模式筆記二十一 —— 中介者模式

中介者模式(Mediator):用一箇中介者物件來封裝一系列的物件互動。中介者物件使各物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立的改變它們之間的互動。中介者模式很容易在系統中應用,也很容易在系統中誤用。當系統出現了“多對多”互動複雜的物件群時,不要急於使用中介者

設計模式 ( 十六 ) 觀察者模式Observer物件行為型

1.概述 一些面向物件的程式設計方式,提供了一種構建物件間複雜網路互連的能力。當物件們連線在一起時,它們就可以相互提供服務和資訊。 通常來說,當某個物件的狀態發生改變時,你仍然需要物件之間能互相通訊。但是出於各種原因,你也許並不願意因為程式碼環境的改變而對程式碼做大

設計模式 十七 狀態模式State物件行為型

                1.概述在軟體開發過程中,應用程式可能會根據不同的情況作出不同的處理。最直接的解決方案是將這些所有可能發生的情況全都考慮到。然後使用if... ellse語句來做狀態判斷來進行不同情況的處理。但是對複雜狀態的判斷就顯得“力不從心了”。隨著增加新的狀態或者修改一個狀體(if el

設計模式 ( 十八 ) 策略模式Strategy物件行為型

1.概述         在軟體開發中也常常遇到類似的情況,實現某一個功能有多種演算法或者策略,我們可以根據環境或者條件的不同選擇不同的演算法或者策略來完成該功能。如查詢、排序等,一種常用的方法是硬編碼(Hard Coding)在一個類中,如需要提供多種查詢演算法,可以