<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Dict.CN 在線詞典, 英語學(xué)習(xí), 在線翻譯

    都市淘沙者

    荔枝FM Everyone can be host

    統(tǒng)計

    留言簿(23)

    積分與排名

    優(yōu)秀學(xué)習(xí)網(wǎng)站

    友情連接

    閱讀排行榜

    評論排行榜

    JAVA DAO編程模式 (zhuan)

    J2EE開發(fā)人員使用數(shù)據(jù)訪問對象(DAO)設(shè)計模式把底層的數(shù)據(jù)訪問邏輯和高層的商務(wù)邏輯分開。實現(xiàn)DAO模式能夠更加專注于編寫數(shù)據(jù)訪問代碼。這篇文章中,Java開發(fā)人員Sean C. Sullivan從三個方面討論DAO編程的結(jié)構(gòu)特征:事務(wù)劃分,異常處理,日志記錄。

      在最近的18個月,我和一個優(yōu)秀的軟件開發(fā)團隊一起工作,開發(fā)定制基于WEB的供應(yīng)鏈管理應(yīng)用程序.我們的應(yīng)用程序訪問廣泛的持久層數(shù)據(jù),包括出貨狀態(tài),供應(yīng)鏈制度,庫存,貨物發(fā)運,項目管理數(shù)據(jù),和用戶屬性等.我們使用JDBC API連接我們公司的各種數(shù)據(jù)庫平臺,并且在整個應(yīng)用程序中應(yīng)用了DAO設(shè)計模式.

      通過在整個應(yīng)用程序中應(yīng)用數(shù)據(jù)訪問對象(DAO)設(shè)計模式使我們能夠把底層的數(shù)據(jù)訪問邏輯和上層的商務(wù)邏輯分開.我們?yōu)槊總€數(shù)據(jù)源創(chuàng)建了提供CRUD(創(chuàng)建,讀取,更新,刪除)操作的DAO類.

      在本文中,我將向你介紹DAO的實現(xiàn)策略以及創(chuàng)建更好的DAO類的技術(shù).我會明確的介紹日志記錄,異常處理,和事務(wù)劃分三項技術(shù).你將學(xué)在你的DAO類中怎樣把這三種技術(shù)結(jié)合在一起.這篇文章假設(shè)你熟悉JDBC API,SQL和關(guān)系性數(shù)據(jù)庫編程.

      我們先來回顧一下DAO設(shè)計模式和數(shù)據(jù)訪問對象.

      DAO基礎(chǔ)

      DAO模式是標(biāo)準的J2EE設(shè)計模式之一.開發(fā)人員使用這個模式把底層的數(shù)據(jù)訪問操作和上層的商務(wù)邏輯分開.一個典型的DAO實現(xiàn)有下列幾個組件:

      1. 一個DAO工廠類;

      2. 一個DAO接口;

      3. 一個實現(xiàn)DAO接口的具體類;

      4. 數(shù)據(jù)傳遞對象(有些時候叫做值對象).

      具體的DAO類包含了從特定的數(shù)據(jù)源訪問數(shù)據(jù)的邏輯。在下面的這段中你將學(xué)到設(shè)計和實現(xiàn)數(shù)據(jù)訪問對象的技術(shù)。

      事務(wù)劃分:

      關(guān)于DAO要記住的一件重要事情是它們是事務(wù)性對象。每個被DAO執(zhí)行的操作(象創(chuàng)建,更新、或刪除數(shù)據(jù))都是和事務(wù)相關(guān)聯(lián)的。同樣的,事務(wù)劃分(transaction demarcation)的概念是特別重要的。

      事務(wù)劃分是在事務(wù)界定定義中的方式。J2EE規(guī)范為事務(wù)劃分描述了兩種模式:編程性事務(wù)(programmatic)和聲明性事務(wù)(declarative)。下表是對這兩種模式的拆分:

    聲明性事務(wù)劃分 編程性事務(wù)劃分
    程序員使用EJB的布署描述符聲明事務(wù)屬性程序員擔(dān)負編寫事務(wù)邏輯代碼的責(zé)任。
    運行時環(huán)境(EJB容器)使用這些屬性來自動的管理事務(wù)。應(yīng)用程序通過一個API接口來控制事務(wù)。

      我將把注意力集中的編程性事務(wù)劃分上。

      象前面的介紹一樣,DAOs是一些事務(wù)對象。一個典型的DAO要執(zhí)行象創(chuàng)建、更新、和刪除這的事務(wù)性操作。在設(shè)計一個DAO時,首先要問自己如下問題:

      1、 事務(wù)將怎樣開始?

      2、 事務(wù)將怎樣結(jié)束?

      3、 那個對象將承擔(dān)起動一個事務(wù)的責(zé)任?

      4、 那個對象將承擔(dān)結(jié)束一個事務(wù)的責(zé)任?

      5、 DAO應(yīng)該承擔(dān)起動和結(jié)束事務(wù)的責(zé)任?

      6、 應(yīng)用程序需要交叉訪問多個DAO嗎?

      7、 一個事務(wù)包含一個DAO還是多個DAO?

      8、 一個DAO包含其它的DAO中的方法嗎?

      回答這些問題將有助于你為DAO對象選擇最好的事務(wù)劃分策略。對ADO中的事務(wù)劃分有兩個主要的策略。一種方法是使用DAO承擔(dān)事務(wù)劃分的責(zé)任;另一種是延期性事務(wù),它把事務(wù)劃分到調(diào)用DAO對象的方法中。如果你選擇前者,你將要在DAO類中嵌入事務(wù)代碼。如果你選擇后者,事務(wù)代碼將被寫在DAO類的外部。我們將使用簡單的代碼實例來更好的理解這兩種方法是怎樣工作的。

      實例1展示了一個帶有兩種數(shù)據(jù)操作的DAO:創(chuàng)建(create)和更新(update):

    public void createWarehouseProfile(WHProfile profile);
    public void updateWarehouseStatus(WHIdentifier id, StatusInfo status);

      實例2展示了一個簡單的事務(wù),事務(wù)劃分代碼是在DAO類的外部。注意:在這個例子中的調(diào)用者把多個DOA操作組合到這個事務(wù)中。

    tx.begin(); // start the transaction
    dao.createWarehouseProfile(profile);
    dao.updateWarehouseStatus(id1, status1);
    dao.updateWarehouseStatus(id2, status2);
    tx.commit(); // end the transaction

      這種事務(wù)事務(wù)劃分策略對在一個單一事務(wù)中訪問多個DAO的應(yīng)用程序來說尤為重要。

      你即可使用JDBC API也可以使用Java 事務(wù)API(JTA)來實現(xiàn)事務(wù)的劃分。JDBC事務(wù)劃分比JTA事務(wù)劃分簡單,但是JTA提供了更好的靈活性。在下面的這段中,我們會進一步的看事務(wù)劃分機制。

      使用JDBC的事務(wù)劃分

      JDBC事務(wù)是使用Connection對象來控制的。JDBC的連接接口(java.sql.Connection)提供了兩種事務(wù)模式:自動提交和手動提交。Java.sql.Connection為控制事務(wù)提供了下列方法:

    .public void setAutoCommit(Boolean)
    .public Boolean getAutoCommit()
    .public void commit()
    .public void rollback()

      實例3展示怎樣使用JDBC API來劃分事務(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ù)劃分,你能夠把多個SQL語句組合到一個單一事務(wù)中。JDBC事務(wù)的缺點之一就是事務(wù)范圍被限定在一個單一的數(shù)據(jù)庫連接中。一個JDBC事務(wù)不能夠跨越多個數(shù)據(jù)庫。接下來,我們會看到怎樣使用JTA來做事務(wù)劃分的。因為JTA不象JDBC那樣被廣泛的了解,所以我首先概要的介紹一下JTA。

      JTA概要介紹

      Java事務(wù)API(JTA;Java Transaction API)和它的同胞Java事務(wù)服務(wù)(JTS;Java Transaction Service),為J2EE平臺提供了分布式事務(wù)服務(wù)。一個分布式事務(wù)(distributed transaction)包括一個事務(wù)管理器(transaction manager)和一個或多個資源管理器(resource manager)。一個資源管理器(resource manager)是任意類型的持久化數(shù)據(jù)存儲。事務(wù)管理器(transaction manager)承擔(dān)著所有事務(wù)參與單元者的相互通訊的責(zé)任。下車站顯示了事務(wù)管理器和資源管理的間的關(guān)系。

      JTA事務(wù)比JDBC事務(wù)更強大。一個JTA事務(wù)可以有多個參與者,而一個JDBC事務(wù)則被限定在一個單一的數(shù)據(jù)庫連接。下列任一個Java平臺的組件都可以參與到一個JTA事務(wù)中:

      .JDBC連接

      .JDO PersistenceManager 對象

      .JMS 隊列

      .JMS 主題

      .企業(yè)JavaBeans(EJB)

      .一個用J2EE Connector Architecture 規(guī)范編譯的資源分配器。

      使用JTA的事務(wù)劃分

      要用JTA來劃分一個事務(wù),應(yīng)用程序調(diào)用javax.transaction.UserTransaction接口中的方法。示例4顯示了一個典型的JNDI搜索的UseTransaction對象。

    import javax.transaction.*;
    import javax.naming.*;
    // ...
    InitialContext ctx = new InitialContext();
    Object txObj = ctx.lookup(";java:comp/UserTransaction";);
    UserTransaction utx = (UserTransaction) txObj;

      應(yīng)用程序有了UserTransaction對象的引用之后,就可以象示例5那樣來起動事務(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()時,事務(wù)管理器使用兩段提交協(xié)議來結(jié)束事務(wù)。JTA事務(wù)控制的方法:

      .javax.transaction.UserTransaction接口提供了下列事務(wù)控制方法:

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


      應(yīng)用程序調(diào)用begin()來起動事務(wù),即可調(diào)用commit()也可以調(diào)用rollback()來結(jié)束事務(wù)。

    使用JTA和JDBC

      開發(fā)人員經(jīng)常使用JDBC來作為DAO類中的底層數(shù)據(jù)操作。如果計劃使用JTA來劃分事務(wù),你將需要一個實現(xiàn)了javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驅(qū)動。實現(xiàn)了這些接口的驅(qū)動將有能力參與到JTA事務(wù)中。一個XADataSource對象是一個XAConnection對象的工廠。XAConnections是參與到JTA事務(wù)中的連接。

      你需要使用應(yīng)用程序服務(wù)器管理工具來建立XADataSource對象。對于特殊的指令請參考應(yīng)用程序服務(wù)器文檔和JDBC驅(qū)動文檔。

      J2EE應(yīng)用程序使用JNDI來查找數(shù)據(jù)源。一旦應(yīng)用程序有了一個數(shù)據(jù)源對象的引用,這會調(diào)用javax.sql.DataSource.getConnection()來獲得數(shù)據(jù)庫的連接。

      XA連接區(qū)別于非XA連接。要記住的是XA連接是一個JTA事務(wù)中的參與者。這就意味著XA連接不支持JDBC的自動提交特性。也就是說應(yīng)用程序不必在XA連接上調(diào)用java.sql.Connection.commit()或java.sql.Connection.rollback()。相反,應(yīng)用程序應(yīng)該使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().

      選擇最好的方法

      我們已經(jīng)討論了JDBC和JTA是怎樣劃分事務(wù)的。每一種方法都有它的優(yōu)點,回此你需要決定為你的應(yīng)用程序選擇一個最適應(yīng)的方法。 在我們團隊許多最近的對于事務(wù)劃分的項目中使用JDBC API來創(chuàng)建DAO類。這DAO類總結(jié)如下:

      .事務(wù)劃分代碼被嵌入到DAO類內(nèi)部

      .DAO類使用JDBC API來進行事務(wù)劃分

      .調(diào)用者沒有劃分事務(wù)的方法

      .事務(wù)范圍被限定在一個單一的JDBC連接

      JDBC事務(wù)對復(fù)雜的企業(yè)應(yīng)用程序不總是有效的。如果你的事務(wù)將跨越多個DAO對象或多個數(shù)據(jù)庫,那么下面的實現(xiàn)策略可能會更恰當(dāng):

      .用JTA對事務(wù)進行劃分

      .事務(wù)劃分代碼被DAO分開

      .調(diào)用者承擔(dān)劃分事務(wù)的責(zé)任

      .DAO參與一個全局的事務(wù)中

      JDBC方法由于它的簡易性而具有吸引力,JTA方法提供了更多靈活性。你選擇什么樣的實現(xiàn)將依賴于你的應(yīng)用程序的特定需求。

      日志記錄和DAO

      一個好的DAO實現(xiàn)類將使用日志記錄來捕獲有關(guān)它在運行時的行為細節(jié)。你可以選擇記錄異常、配置信息、連接狀態(tài)、JDBC驅(qū)動程序的元數(shù)據(jù)或查詢參數(shù)。日志對開發(fā)整個階段都是有益的。我經(jīng)常檢查應(yīng)用程序在開發(fā)期間、測試期間和產(chǎn)品中的日志記錄。

      在這段中,我們將展現(xiàn)一段如何把Jakarta Commaons Logging結(jié)合中一個DAO中的例子。在我們開始之前,讓我們先回顧一些基礎(chǔ)知識。

      選擇一個日志例庫

      許多開發(fā)人員使用的基本日志形式是:System.out.println和System.err.println.Println語句。這種形式快捷方便,但它們不能提供一個完整的日志系統(tǒng)的的能力。下表列出了Java平臺的日志類庫:

    日志類庫開源嗎?URL
    Java.util.logging http://java.sun.com/j2ee
    Jakarta Log4jhttp://hajarta.apache.org/log4j/
    Jakarta Commons Logginghttp:/Jakarta.apache.org/commons/logging.html

      Java.util.logging是J2SE1.4平臺上的標(biāo)準的API。但是,大多數(shù)開發(fā)人員都認為Jakarta Log4j提供了更大的功能性和靈活性。Log4j超越j(luò)ava.util.logging的優(yōu)點之一就是它支持J2SE1.3和J2SE1.4平臺。

      Jakarta Commons Logging能夠被用于和java.util.loggin或Jakarta Log4j一起工作。Commons Logging是一個把你的應(yīng)用程序獨立于日志實現(xiàn)的提取層。使用Commons Logging你能夠通過改變一個配置文件來與下面的日志實現(xiàn)來交換數(shù)據(jù)。Commons Logging被用于JAKARTA Struts1.1和Jakarta HttpClient2.0中。

      一個日志示例

      示例7顯示了在一個DOA類中怎樣使用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 ...
    }
    }
    }

      日志是評估應(yīng)用程序的基本部分。如果你在一個DAO中遇到了失敗,日志經(jīng)常會為理解發(fā)生的什么錯誤提供最好的信息。把日志結(jié)合到你的DAO中,確保得到調(diào)試和解決問題的有效手段。

      DAO中的異常處理

      我們已經(jīng)看了事務(wù)劃分和日志記錄,并且現(xiàn)在對于它們是怎樣應(yīng)用于數(shù)據(jù)訪問對象的有一個深入的理解。我們第三部分也是最后要討論的是異常處理。下面的一些簡單的異常處理方針使用你的DAO更容易使用,更加健壯和更具有可維護性。

      在實現(xiàn)DAO模式的時候,要考濾下面的問題:

      .在DAO的public接口中的方法將拋出被檢查的異常嗎?

      .如果是,將拋出什么樣的檢查性異常?

      .在DAO實現(xiàn)類中怎能樣處理異常。

      在用DAO模式工作的過程中,我們的團隊為異常處理開發(fā)了一組方針。下面的這些方針會很大程度的改善你的DAO:

      .DAO方法應(yīng)該拋出有意義的異常。

      .DAO方法不應(yīng)該拋出java.lang.Exception異常。因為java.lang.Exception太一般化,它不能包含有關(guān)潛在問題的所有信息。

      .DAO方法不應(yīng)該拋出java.sql.SQLException異常。SQLException是一個底層的JDBC異常,DAO應(yīng)用努力封裝JDBC異常而不應(yīng)該把JDBC異常留給應(yīng)用程序的其它部分。

      .在DAO接口中的方法應(yīng)該只拋出調(diào)用者期望處理的檢查性異常。如果調(diào)用者不能用適當(dāng)?shù)姆椒▉硖幚懋惓?,考濾拋出不檢查性(運行時run-time)異常。

      .如果你的數(shù)據(jù)訪問代碼捕獲了一個異常,不可要忽略它。忽略捕獲異常的DAO是很處理的。

      .使用異常鏈把底層的異常傳遞給高層的某個處理器。

      .考濾定義一個標(biāo)準的DAO異常類。Spring框架提供了一個優(yōu)秀的預(yù)定義的DAO異常類的集合。

      看Resources,查看有異常和異常處理技術(shù)的更詳細信息。

      實現(xiàn)示例:MovieDAO

      MoveDAO是一個示范了在這篇文章中所討論的所有技術(shù),包括事務(wù)劃分、日志記錄和異常處理。你會在Resources段找到MovieDAO的源代碼。它被分下面的三個包:

    .daoexamples.exception
    .daoexamples.move
    .daoexamples.moviedemo

      這個DAO模式的實現(xiàn)由下面的類和接口組成:

    .daoexamples.movie.MovieDAOFactory
    .daoexamples.movie.MovieDAO
    .daoexamples.movie.MovieDAOImpl
    .daoexamples.movie.MovieDAOImplJTA
    .daoexamples.movie.Movie
    .daoexamples.movie.MovieImple
    .daoexamples.movie.MovieNotFoundException
    .daoexamples.movie.MovieUtil

      MovieDAO接口定義了DAO的數(shù)據(jù)操作。這個接口有如下五個方法:

    .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接口的實現(xiàn)。每個實現(xiàn)使用了一個同的事務(wù)劃分方法,如下表所示:

    ?MovieDAOImplMovieDAOImplJTA
    實現(xiàn)了MovieDAO接口嗎?YesYes
    通過JNDI獲得DataSource嗎?Yes Yes
    從一個DataSource獲得java.sql.Connection對象嗎?Yes Yes
    DAO界定內(nèi)部的事務(wù)嗎?Yes No
    使用JDBC事務(wù)嗎?YesNo
    使用一個XA DataSource嗎?No Yes
    分擔(dān)JTA事務(wù)嗎?No Yes

      MovieDAO 示范應(yīng)用程序

      這個示范應(yīng)用程序是一個叫做daoexamples.moviedemo.DemoServlet.DemoServlet的servlet類,它使用Movie DAO來查詢和更新一個表中的movie數(shù)據(jù)。

      這個servlet示范了把JTA感知的MovieDAO和Java消息服務(wù)組合到一個單一的事務(wù)中,如示例8所示:

    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īng)用程序,在你的應(yīng)用程序服務(wù)器中配置一個XA 數(shù)據(jù)源和一個非XA數(shù)據(jù)源。然后布署daoexamples.ear文件。這個應(yīng)用程序?qū)⑦\行在任何與J2EE兼容的應(yīng)用程序服務(wù)器。


    ?
    =====================================================
    很多的J2EE應(yīng)用程序需要使用持久性數(shù)據(jù)(數(shù)據(jù)庫、文件等)。不同的程序,持久性存儲是各不相同的,并且用來訪問這些不同的持久性存儲機制的API也有很大的不同。如果應(yīng)用程序要在不同的持久性存儲間遷移,這些訪問特定持久存儲層的代碼將面臨重寫。
      
      如何解決這個問題?且看"DAO模式"
      
      數(shù)據(jù)訪問對象(Data Acess Object) 模式
      
      一.環(huán)境
      根據(jù)數(shù)據(jù)源不同,數(shù)據(jù)訪問也不同。根據(jù)存儲的類型(關(guān)系數(shù)據(jù)庫、面向?qū)ο髷?shù)據(jù)庫、文件等等)和供應(yīng)商實現(xiàn)不同,持久性存儲(比如數(shù)據(jù)庫)的訪問差別也很大。
      
      二.問題
      許多真是的J2EE應(yīng)用程序需要在一定程度上使用持久性數(shù)據(jù)。對于許多應(yīng)用程序,持久性存儲是使用不同的機制實現(xiàn)的,并且用來訪問這些不同的持久性存儲機制的API也有很大的不同。
      比如,應(yīng)用程序使用實體bean(這里應(yīng)該是指BMP的bean,CMP的bean已大大降低了與RDBMS的耦合)的分布式組件來表示持久性數(shù)據(jù),或者使用JDBC API來訪問駐留在某關(guān)系數(shù)據(jù)庫管理系統(tǒng)(RDBMS)中的數(shù)據(jù),這些組件中包含連接性性和數(shù)據(jù)訪問代碼會引入這些組件與數(shù)據(jù)源實現(xiàn)之間的緊密耦合。組件中這類代碼依賴性使應(yīng)用程序從某種數(shù)據(jù)源遷移到其他種類的數(shù)據(jù)源將變得非常麻煩和困難。當(dāng)數(shù)據(jù)源變化時,組件也需要改變,以便于能夠處理新類型的數(shù)據(jù)源。
      
      (舉個例子來說,我們UPTEL系統(tǒng)是使用JDBC API對 ORACLE數(shù)據(jù)庫進行連接和數(shù)據(jù)訪問的,這些JDBC API與SQL語句散布在系統(tǒng)中,當(dāng)我們需要將UPTEL遷移到其他RDBMS時,比如曾經(jīng)遷移到INFORMIX,就面臨重寫數(shù)據(jù)庫連接和訪問數(shù)據(jù)的模塊。)
      
      三.作用力
      1.諸如bean管理的實體bean、會話bean、servlet等組件往往需要從持久性存儲數(shù)據(jù)源中檢索數(shù)據(jù),以及進行數(shù)據(jù)存儲等操作。
      2.根據(jù)產(chǎn)品供應(yīng)商的不同,持久性存儲API差別也很大,這些API和其能力同樣根據(jù)存儲的類型不同也有差別,這樣存在以下缺點,即訪問這些獨立系統(tǒng)的API很不統(tǒng)一。
      3.組件需要透明于實際的持久性存儲或者數(shù)據(jù)源實現(xiàn),以便于提供到不同供應(yīng)商產(chǎn)品、不同存儲類型和不同數(shù)據(jù)源類型的更容易的移植性。
      
      四.解決方案
      使用數(shù)據(jù)訪問對象(DAO)模式來抽象和封裝所有對數(shù)據(jù)源的訪問。DAO管理著與數(shù)據(jù)源的連接以便檢索和存儲數(shù)據(jù)。
      DAO實現(xiàn)了用來操作數(shù)據(jù)源的訪問機制。數(shù)據(jù)源可以時RDBMS,LDAP,File等。依賴于DAO的業(yè)務(wù)組件為其客戶端使用DAO提供更簡單的接口。DAO完全向客戶端隱藏了數(shù)據(jù)源實現(xiàn)細節(jié)。由于當(dāng)?shù)蛯訑?shù)據(jù)源實現(xiàn)變化時,DAO向客戶端提供的接口不會變化,所有該模式允許DAO調(diào)整到不同的存儲模式,而不會影響其客戶端或者業(yè)務(wù)組件。重要的是,DAO充當(dāng)組件和數(shù)據(jù)源之間的適配器。
      
      (按照這個理論,如果我們UPTEL系統(tǒng)使用了DAO模式,就可以無縫的從ORACLE遷移到任何一個RDBMS了。夢想總是很完美的,且看看DAO模式如何實現(xiàn))
      
      1.結(jié)構(gòu),圖1是表示DAO模式中各種關(guān)系的類圖。
      
      此主題相關(guān)圖片如下:
      
     

      2.參與者和職責(zé)
      1)BusinessObject(業(yè)務(wù)對象)
      代表數(shù)據(jù)客戶端。正是該對象需要訪問數(shù)據(jù)源以獲取和存儲數(shù)據(jù)。
      2)DataAccessObject(數(shù)據(jù)訪問對象)
      是該模式的主要對象。DataAccessObject抽取該BusinessObject的低層數(shù)據(jù)訪問實現(xiàn),以保證對數(shù)據(jù)源的透明訪問。BusinessObject也可以把數(shù)據(jù)加載和存儲操作委托給DataAccessObject。
      3)DataSource(數(shù)據(jù)源)
      代表數(shù)據(jù)源實現(xiàn)。數(shù)據(jù)源可以是各RDBMSR數(shù)據(jù)庫,OODBMS,XML文件等等。
      4)valueObject(值對象)
      代表用做數(shù)據(jù)攜帶著的值對象。DataAccessObject可以使用值對象來把數(shù)據(jù)返回給客戶端。
      DataAccessObject也許會接受來自于客戶端的數(shù)據(jù),其中這些用于更新數(shù)據(jù)源的數(shù)據(jù)存放于值對象中來傳遞。
      
      3.策略
      1).自動DAO代碼產(chǎn)生策略
      因為每個BusinessObject對應(yīng)于一個特殊的DAO,因此有可能建立BusinessObject,DAO和低層實現(xiàn)(比如RDBMS中的表)之間的關(guān)系(映射)。一點這些關(guān)系(映射)已經(jīng)建立,我們就可以編寫與應(yīng)用程序有館的代碼生成的簡單工具了(什么?自己寫GP程序?用ORM的附帶工具自動生成不就完了,最多自己寫幾個Adapter,牛人就是不同,啥都要自己寫...),其中的工具可以產(chǎn)生該應(yīng)用程序需要的所有DAO代碼。
      如果DAO需求很復(fù)雜,我們可以采用第三方工具,其中這些工具提供對象到RDBMS數(shù)據(jù)庫的關(guān)系映射(這里指的是前面提到的ORM工具,全稱是Object Relation Mapping,目前成熟的ORM工具有很多:Hibernate,OJB,Torque,TopLink等等)。
      這些工具通常包含GUI工具來把業(yè)務(wù)對象映射到持久性存儲對象,并且因而定義中間DAO。一旦這些映射完成,這些工具會自動地生成代碼,并且也許會提供其他增值功能,比如結(jié)果緩沖、查詢緩沖、與應(yīng)用程序集成,以及與其他第三方產(chǎn)品(比如分布式緩沖)地繼承,等等。
      (增值服務(wù):Torque提供了結(jié)果緩沖,Hibernate提供了對Oracle數(shù)據(jù)庫SQL指令的優(yōu)化,OJB提供JDO API、OMDB API)
      
      2).數(shù)據(jù)訪問對象的工廠策略
      通過調(diào)整抽象工廠和工廠方法模式,DAO模式可以達到很高的靈活度。
      當(dāng)?shù)蛯哟鎯Σ粫S著實現(xiàn)變化而變化時,該策略可以使用工廠方法模式來實現(xiàn)該策略。以產(chǎn)生應(yīng)用程序需要的大量DAO。圖2是這種情況下的類圖。
      
      此主題相關(guān)圖片如下:
      
     

      當(dāng)?shù)蛯哟鎯﹄S著實現(xiàn)變化而變化時,該策略可以使用抽象工廠方法模式而實現(xiàn)。
      圖3是這種情況下的類圖。
      
      此主題相關(guān)圖片如下:
      

      5.結(jié)果
      1).啟用透明性
      業(yè)務(wù)對象可以是使用數(shù)據(jù)源,而無須了解該數(shù)據(jù)源實現(xiàn)的具體細節(jié)。訪問是透明的,原因是實現(xiàn)被隱藏在DAO的內(nèi)部。
      2).啟用更容易的遷移
      DAO層使應(yīng)用程序更加容易地遷移到一個不同的數(shù)據(jù)庫實現(xiàn)。業(yè)務(wù)對象不了解低層數(shù)據(jù)實現(xiàn)。因而,該遷移只涉及對DAO層的變化。更進一步說,如果使用工廠策略,則有可能為每一個低層存儲實現(xiàn)提供一個具體工廠實現(xiàn)。在這種情況下,遷移到不同的遷移實現(xiàn)意味著給應(yīng)用程序提供一個新的工廠實現(xiàn)。
      3).減少業(yè)務(wù)對象中代碼復(fù)雜度
      由于DAO管理所有的數(shù)據(jù)訪問復(fù)雜性,它可以簡化業(yè)務(wù)對象和其他使用DAO的客戶端中的代碼。所有與實現(xiàn)有關(guān)的代碼(比如sql語句)都被包含在DAO中,而不是包含在業(yè)務(wù)對象中。這樣做提高了代碼的可讀性,已經(jīng)代碼生產(chǎn)效率。
      4).把所有的數(shù)據(jù)訪問集中到一個獨立的層。
      因為所有的數(shù)據(jù)訪問操作現(xiàn)在被委托給DAO,所有單獨的數(shù)據(jù)訪問層可以被看作把數(shù)據(jù)訪問實現(xiàn)與應(yīng)用程序中的其他代碼相隔離的。這種集中化使應(yīng)用程序更容易地維護和管理。
      5).不適用于容器管理的持久性
      由于EJB容器用容器管理的持久性(CMP)來管理實體bean,該容器會自動地服務(wù)所有的持久性存儲訪問。使用容器管理的實體bean的應(yīng)用程序不需要DAO層,因為該應(yīng)用程序服務(wù)器透明地提供該功能。然而,當(dāng)需要組合使用CMP和BMP時,DAO仍舊有用處。
      6).添加其他層
      DAO會在數(shù)據(jù)客戶端和數(shù)據(jù)源之間創(chuàng)建其他的對象層,其中該數(shù)據(jù)源需要被設(shè)計和實現(xiàn)以便于權(quán)衡該模式的好處。但是選擇本方法也會帶來額外的開銷。
      7).需要類層次設(shè)計
      在使用工廠策略時,我們需要設(shè)計和實現(xiàn)具體工廠的層次,以及這些工廠產(chǎn)生的具體產(chǎn)品層次。如果能夠確保這種靈活性,則有必要考慮這種額外的工作。這樣做會增加設(shè)計的復(fù)雜性。然而,在實現(xiàn)該工廠策略時,你可以首先考慮工廠方法模式,然后再根據(jù)需要過渡到抽象工廠。
      
      六.范例代碼
      1.實現(xiàn)數(shù)據(jù)訪問對象模式
      范例9-4時表示Customer信息的持久性對象的DAO范例代碼。當(dāng)findCustomer()被調(diào)用時,CloudscapeCustomerDAO創(chuàng)建一個Customer值對象。
      范例9-6是使用DAO的范例代碼。
      
      2.實現(xiàn)數(shù)據(jù)訪問對象的工廠策略
      1)使用工廠方法模式
      2)使用抽象工廠模式
      范例代碼9-2是CloudscapeDAOFactory的范例代碼。
      范例代碼9-3中的CustomerDAO接口為Customer持久性對象定義了DAO方法,這些接口是被所有具體DAO實現(xiàn)來實現(xiàn)的,比如CloudscapeCustomerDAO、OracleCustomerDAO、已經(jīng)SybaseCustomerDAO。Account和OrederDAO接口也與此類似。
      
      Example 9.1 Abstract DAOFactory Class
      
      // Abstract class DAO Factory
      public abstract class DAOFactory {
      
      // List of DAO types supported by the factory
      public static final int CLOUDSCAPE = 1;
      public static final int ORACLE = 2;
      public static final int SYBASE = 3;
      ...
      
      // There will be a method for each DAO that can be
      // created. The concrete factories will have to
      // implement these methods.
      public abstract CustomerDAO getCustomerDAO();
      public abstract AccountDAO getAccountDAO();
      public abstract OrderDAO getOrderDAO();
      ...
      
      public static DAOFactory getDAOFactory(
      int whichFactory) {
      
      switch (whichFactory) {
      case CLOUDSCAPE:
      return new CloudscapeDAOFactory();
      case ORACLE :
      return new OracleDAOFactory();
      case SYBASE :
      return new SybaseDAOFactory();
      ...
      default :

    posted on 2007-01-25 17:47 都市淘沙者 閱讀(2623) 評論(1)  編輯  收藏 所屬分類: Java Basic/Lucene/開源資料

    評論

    # re: JAVA DAO編程模式 (zhuan) 2009-04-17 10:01 polaris

    Resource到什么地方下呢?  回復(fù)  更多評論   

    主站蜘蛛池模板: 亚洲精品国产成人| 羞羞视频免费网站日本| 亚洲AV无码久久精品狠狠爱浪潮| 日本大片在线看黄a∨免费| 99久久精品免费精品国产| 国产精品永久免费| 国产亚洲蜜芽精品久久| 国产成人亚洲综合网站不卡| 亚洲视频在线免费看| 久久精品国产亚洲av成人| 亚洲日本乱码在线观看| 亚洲人成人网站在线观看| 国产成人精品免费视频大全五级| 成人免费午夜无码视频| **真实毛片免费观看| 午夜影院免费观看| 久久伊人免费视频| 精品国产一区二区三区免费| 在线观看黄片免费入口不卡| 一级做a爱过程免费视| 四虎国产精品永免费| 又黄又大的激情视频在线观看免费视频社区在线 | 精品无码免费专区毛片| 七色永久性tv网站免费看| 中文字幕av免费专区| 三级黄色片免费看| 国产在线观看免费av站| 国产线视频精品免费观看视频| a级毛片高清免费视频就| 中国videos性高清免费| 久操免费在线观看| 香港a毛片免费观看 | 亚洲第一精品在线视频| 亚洲午夜免费视频| 亚洲国产精品美女| 亚洲人成综合网站7777香蕉 | 在线观看免费精品国产| 国产猛烈高潮尖叫视频免费 | 中文在线日本免费永久18近| 亚洲一区二区三区免费| 中文精品人人永久免费 |