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

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

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

    風人園

    弱水三千,只取一瓢,便能解渴;佛法無邊,奉行一法,便能得益。
    隨筆 - 99, 文章 - 181, 評論 - 56, 引用 - 0
    數(shù)據(jù)加載中……

    DaoZero:讓它為你實現(xiàn)DAO接口

    1. DaoZero是什么?它可以在哪方面幫助我?

    *假設(shè)你具有使用Spring的iBatis支持類作為持久層實現(xiàn)的實際編碼經(jīng)驗(即時沒有,學習Spring和iBatis也應(yīng)該不是件怎么難的事情)。

    DaoZero是1個很小的Spring Java Bean。可以到http://dao-zero.sourceforge.net下載。使用DaoZero可以減少基于 iBatis+Spring的持久層代碼數(shù)量,因為DaoZero會動態(tài)地替我們實現(xiàn)持久層接口。它不是1個Spring中iBatis支持類的包裝,而是用來直接替換掉我們手工編寫的持久層實現(xiàn)代碼的。使用DaoZero時,一旦我們完成了DAO接口的定義(Java Interface),通常情況下,我們只需要再在Spring Context定義文件中聲明類型(class)為daozero.ibatis.Dao的bean,并且設(shè)置這些bean的targetType屬性為已定義好的DAO接口,然后這些DaoZero bean 就會在運行時為我們動態(tài)地生成實現(xiàn)了targetType的DAO實現(xiàn)類,由這些實現(xiàn)類去調(diào)用iBatis API訪問數(shù)據(jù)庫。所以,不需要DAO接口的實現(xiàn)代碼了。

    2. DaoZero的工作原理

    DaoZero約定iBatis SQL Mapping XML文件中定義的statement的名字需要和DAO接口(抽象類)的method的名字保持一致,而且,當前版本還要求statement的parameter的數(shù)量及首次出現(xiàn)順序也必須要和DAO接口(抽象類)的method的參數(shù)(形參)的數(shù)量及出現(xiàn)順序保持一致,通過做出這些約定(應(yīng)該不太難于遵守吧),DaoZero就可以確定如何把method被調(diào)用時傳入的參數(shù)(實參)和statement的 parameter對應(yīng)起來,于是就可以用這些傳入的參數(shù)組成statement需要的parameter map,去調(diào)用iBatis API訪問數(shù)據(jù)庫。DaoZero是一個實現(xiàn)了org.springframework.beans.factory.FactoryBean 的bean,就是說它是可以產(chǎn)生bean的factory bean,而DaoZero factory bean產(chǎn)生的bean就是實現(xiàn)了DAO接口的DAO對象,這些DAO對象負責調(diào)用Spring的iBatis template的方法,例如queryForObject()、queryForList()和update()等。這些DAO對象也有足夠“智能”,它們會依據(jù)method的返回類型推斷出該調(diào)用queryForObject()還是queryForList()(當前版本尚不支持queryForMap)。 DaoZero factory bean是如何產(chǎn)生DAO對象的呢?這要視其屬性targetType是接口還是抽象類來定:如果targetType是接口,那么使用JDK標準的 proxy(java.lang.reflect.Proxy)機制,由該proxy負責攔截下對該接口方法的調(diào)用;如果是抽象類,那么就使用CGLIB的enhancer(net.sf.cglib.proxy.Enhancer)萊攔截下對該抽象類中抽象方法的調(diào)用,而將方法調(diào)用攔截下來后的處理則基本上一致。使用JDK Proxy或CGLIB enhancer對性能的影響在數(shù)百納秒(ns)這個數(shù)量級,因此對于大多數(shù)Web應(yīng)用來說相對于數(shù)據(jù)庫SQL執(zhí)行是可以忽略不計的。

    事實上DaoZero不得不hack了一些iBatis的代碼,不得不把iBatis提供的一些接口強行轉(zhuǎn)型(Cast)到iBatis的內(nèi)部實現(xiàn)類,原因在于iBatis似乎沒有提供檢索其statement元數(shù)據(jù)的方法,使得DaoZero不得不在代碼中留下了一些壞味道。(所以,如果iBatis出現(xiàn)了大的版本改變,那么DaoZero這部分代碼也不得不重新寫。)

    3. 用DaoZero代替原來的iBatis DAO bean

    假設(shè)我們有一個數(shù)據(jù)庫表叫"account",表結(jié)構(gòu)如下所示,

    create table account (
    userid varchar(80) not null,
    email varchar(80) not null,
    constraint pk_account primary key (userid)
    );


    我們使用了一個叫Account的domain class來代表該表,Account是標準的Java Bean(POJO),具有屬性:"userId"和"email",

    public class Account implements Serializable {
    private String userid;
    private String email;
    public String getUserId() { return this.userid; }
    public void setUserId(String s) { this.userid=s; }
    public String getEmail() { return this.email; }
    public void setEmail(String s) { this.email=s; }
    }


    操作Account的DAO接口是這樣的,

    public interface AccountDao {
    Account getAccountByUserId(String userId) throws DataAccessException;
    void updateAccount(Account account) throws DataAccessException;
    List getUsernameList() throws DataAccessException;
    }



    使用DaoZero之前,一般情況下,我們會用iBatis做一個DAO實現(xiàn)類,該類繼承自Spring的SqlMapClientDaoSupport,該基類封裝了iBatis SqlMapClient的主要操作以和Spring集成起來,該實現(xiàn)類可能是這樣的:

    import org.springframework.org.ibatis.support.SqlMapClientDaoSupport;

    public class AccountDaoImpl extends SqlMapClientDaoSupport implements AccountDao {
    ?? public Account getAccountByUserIdAndEmail(String userId, String email) throws DataAccessException {
    ????Map params = new HashMap();
    ????params.put( "userId", userId );
    ????params.put( "email", email );
    ????return getTemplate().queryForObject( "getAccountByUserIdAndEmail", params );
    ?? }

    ??public int updateAccount(Account account) throws DataAccessException {
    ????return getTemplate().update( "updateAccount", account );
    ?? }
    ?? public List getUsernameList() throws DataAccessException;
    ????return getTemplate().queryForList( "getUsernameList", null );
    ?? }


    自然,iBatis的SQL Mapping XML文件是必不可少的:

    <select id="getAccountByUserIdAndEmail" resultClass="Account">
    ????select * from account where userid=#userId# AND email=#email#
    </select>

    <select id="getUsernameList" resultClass="java.lang.String">
    ????select userid from account
    </select>

    <update id="updateAccount">
    ????update account set email = #email# where userid=#userId#
    </update>


    然后,我們通常會到Spring Context XML文件中為該DAO聲明1個Spring Bean?:

    <bean id="accountDao" class="AccountDaoImpl">
    ???? <property name="sqlMapClient" ref="sqlMapClient"/>
    </bean>


    現(xiàn)在,我們來試試看使用了DaoZero后DaoZero怎樣來去掉AccountDaoImpl那些繁復無聊的代碼:很簡單,第一步是刪掉那個AccountDaoImpl.java! 然后,修改上面那段Spring Context XML文件中bean的定義,改成:

    <bean id="accountDao" class="daozero.ibatis.Dao">
    ???? <property name="sqlMapClient" ref="sqlMapClient"/>
    ????<property name="targetType" value="AccountDao" /> <!-- interface -->
    </bean>


    可以看到,新的使用DaoZero的方式用的bean的class是DaoZero庫提供的1個固定的類--"daozero.ibatis.Dao"該類會在運行時自動提供AccountDao接口的實現(xiàn)類,所以AccountDaoImpl.java就可以扔掉了,就這么簡單。

    4. 使用抽象類的例子

    雖然上述例子足以應(yīng)付多數(shù)情況,但是DaoZero不可能為我們完成任何事情,有時候還是有不得不手工實現(xiàn)一些DAO方法的需要的,這時候我們?nèi)绾渭缺A粝翫aoZero提供的好處, 又能夠告訴DaoZero哪些方法我們已經(jīng)自己手工實現(xiàn)了而不需要DaoZero代勞了呢?解決辦法是很自然的,寫好我們自己的DAO類,但是只需要填上需要手工實現(xiàn)的,其他的可以繼續(xù)由DaoZero代勞, DaoZero會依據(jù)該實現(xiàn)類的某方法是否是abstract來判斷是否需要替我們?nèi)プ鍪虑椋恍枰脑捑褪裁匆膊蛔觯苯愚D(zhuǎn)交給我們填好的方法代碼,所以,這時候的DAO實現(xiàn)類是抽象類。另外需要做的事情就是把bean的targetType換成這個abstract的DAO實現(xiàn)類。對于上面那個例子,我們保留下AccountDaoImpl.java,手工填寫updateAccount()方法:

    public abstract class AccountDaoImpl implements AccountDao {
    public abstract int __updateAccount(Account account) throws DataAccessException;
    public int updateAccount(Account account) throws DataAccessException {
    ????// Insert additional operation code here
    ????return __updateAccount(account);
    }
    }


    最后,需要修改SQL mapped statement的名字,改成"__updateAccount",以便讓DaoZero了解statement __updateAccount是和DAO方法__updateAccount聯(lián)系在一起的:

    <select id="getAccountByUserIdAndEmail" resultClass="Account">
    ????select * from account where userid=#userId# AND email=#email#
    </select>

    <select id="getUsernameList" resultClass="java.lang.String">
    ????select userid from account
    </select>

    <update id="__updateAccount">
    ????update account set email = #email# where userid=#userId#
    </update>


    當然,DaoZero并不反對你不修改statement名字,不增加一個__updateAccount方法,而是在updateAccount()方法中按照從前的寫法自己調(diào)用iBatis API(不過,既然改改statement的名字 就可以讓DaoZero繼續(xù)為我們服務(wù),而且能保持代碼的一致性,我想通常還是加上個__updateAccount方法更合適一些,這也是DaoZero推薦的一個實踐 -- DaoZero希望你關(guān)注于完成DaoZero替你 代勞不了的事情,而不是去寫那些重復性很大的代碼。)

    5. 使用當前版本的DaoZero的一些限制條件

    # 同一個類中不允許有同名方法(名字重載),除非這些同名方法的參數(shù)個數(shù)不一樣(否則,DaoZero為statement尋找對應(yīng)方法時會因出現(xiàn)歧義而失敗)。
    # 由DaoZero負責實現(xiàn)的抽象方法必須是public abstract。因為當前版本的DaoZero使用Java標準的Reflection機制(Class.getMethods())來遍歷DAO類的method,所以非public abstract的方法是找不到的,這是一個可以改進的限制條件 -- DaoZero計劃在后續(xù)版本中自行分析class文件來找到protected abstract方法,這樣就可以不用強迫我們不得不把內(nèi)部方法也public出來了;
    # 目前DaoZero尚不支持iBatis API中的queryForMap()方法和Pagination機制(queryForMap在實現(xiàn)計劃之中,而pagination我正考慮如何實現(xiàn),而且既然使用iBatis就是為了獲得使用native SQL 的靈活性和性能,我個人更傾向于不使用iBatis的pagination作為分頁支持機制,而習慣于利用數(shù)據(jù)庫SQL對分頁的支持語法);
    # 雖然目前只支持iBatis,但為Hibernate給出一個DaoZero實現(xiàn)也是在計劃之中(因為我和不少人一樣,也喜歡Hibernate);

    6. 使用時出現(xiàn)問題?

    # 確保參數(shù)的數(shù)量和首次出現(xiàn)順序在statement和method中是保持一致的,而且必須是abstract,根據(jù)使用經(jīng)驗,大多數(shù)錯誤來自于此;
    # 看看是否滿足第5節(jié)說明的一些限制條件,很可能忽略的一種情況就是把method做成protected abstract了。

    7. 其他

    實際上還有1個小技巧:namespace -- 是的,這可以用于支持iBatis的namespace機制,但是1個Dao只能限定于1個namespace。具體使用方法請參照下載下來的sample。Sample是修改自Spring的JPetstore例子,比較一下它和原始的Spring的JPetstore的實現(xiàn)例子,可以找到DaoZero提倡的如何在service層使用DAO的理念,例如DaoZero更提倡不要只把service作為dao層的delegation,提倡大部分對DAO的操作的組合都放到service層中去。

    8. License:

    Apache License Version 2.0

    posted on 2006-07-05 17:54 風人園 閱讀(269) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 国产大片91精品免费看3| 无码av免费毛片一区二区| 人妻仑刮八A级毛片免费看| 真人无码作爱免费视频| 好吊色永久免费视频大全| 国产精品高清免费网站| 黄在线观看www免费看| 日日AV拍夜夜添久久免费| 亚洲人成网7777777国产| 亚洲国产精品国自产电影| 亚洲导航深夜福利| 免费一区二区无码视频在线播放| 成人免费视频国产| 免费人成视频在线观看免费| JLZZJLZZ亚洲乱熟无码| 亚洲伊人色一综合网| 野花高清在线观看免费完整版中文 | 国产精品亚洲天堂| 国产又黄又爽又刺激的免费网址| AV激情亚洲男人的天堂国语| 一边摸一边爽一边叫床免费视频| 24小时免费看片| 免费永久看黄在线观看app| 久久精品国产亚洲av高清漫画| 曰批全过程免费视频免费看| 亚洲视频在线免费| 亚洲电影免费在线观看| 免费jjzz在在线播放国产| 亚洲性69影院在线观看| 日本牲交大片免费观看| 国产久爱免费精品视频| 亚洲国产成人精品不卡青青草原| 曰批全过程免费视频在线观看| 精品亚洲福利一区二区| 亚洲国产精品无码久久久蜜芽| 337P日本欧洲亚洲大胆精品| 亚洲欧洲日本在线| 色窝窝亚洲av网| 精品久久香蕉国产线看观看亚洲| 亚洲色偷偷综合亚洲av78| 日本免费在线观看|