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

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

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

    風(fēng)人園

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

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

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

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

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

    2. DaoZero的工作原理

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

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

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

    假設(shè)我們有一個(gè)數(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)
    );


    我們使用了一個(gè)叫Account的domain class來代表該表,Account是標(biāo)準(zhǔn)的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做一個(gè)DAO實(shí)現(xiàn)類,該類繼承自Spring的SqlMapClientDaoSupport,該基類封裝了iBatis SqlMapClient的主要操作以和Spring集成起來,該實(shí)現(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個(gè)Spring Bean?:

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


    現(xiàn)在,我們來試試看使用了DaoZero后DaoZero怎樣來去掉AccountDaoImpl那些繁復(fù)無聊的代碼:很簡單,第一步是刪掉那個(gè)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個(gè)固定的類--"daozero.ibatis.Dao"該類會在運(yùn)行時(shí)自動提供AccountDao接口的實(shí)現(xiàn)類,所以AccountDaoImpl.java就可以扔掉了,就這么簡單。

    4. 使用抽象類的例子

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


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

    5. 使用當(dāng)前版本的DaoZero的一些限制條件

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

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

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

    7. 其他

    實(shí)際上還有1個(gè)小技巧:namespace -- 是的,這可以用于支持iBatis的namespace機(jī)制,但是1個(gè)Dao只能限定于1個(gè)namespace。具體使用方法請參照下載下來的sample。Sample是修改自Spring的JPetstore例子,比較一下它和原始的Spring的JPetstore的實(shí)現(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 風(fēng)人園 閱讀(267) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 国产精品亚洲精品日韩动图| a在线免费观看视频| 免费国产高清视频| 中文字幕免费人成乱码中国| 亚洲欧洲第一a在线观看| 最新仑乱免费视频| 午夜免费国产体验区免费的| 亚洲avav天堂av在线不卡| 岛国av无码免费无禁网站| eeuss免费影院| 亚洲天堂一区二区三区| 亚洲精品国产精品乱码不卡| 99国产精品免费观看视频| 亚洲AV无码成人网站在线观看| 国产亚洲色婷婷久久99精品| 女人让男人免费桶爽30分钟| 99re6在线精品免费观看| 亚洲日本中文字幕天天更新| 国产亚洲精品美女久久久 | 91免费在线视频| 亚洲日本VA中文字幕久久道具| 国产精品亚洲A∨天堂不卡| 好爽又高潮了毛片免费下载| 午夜免费啪视频在线观看 | 亚洲免费黄色网址| 亚洲美女又黄又爽在线观看| 四虎www成人影院免费观看| 好紧我太爽了视频免费国产 | 美女在线视频观看影院免费天天看 | 亚欧色视频在线观看免费| 一级特黄色毛片免费看| 亚洲人成电影网站色www| 亚洲男人都懂得羞羞网站| 亚洲欧洲日产国码一级毛片| 免费精品一区二区三区在线观看| 国产va在线观看免费| 久久久久久久久久免免费精品 | 久久亚洲精品无码aⅴ大香| 浮力影院亚洲国产第一页| 国产成人高清精品免费软件| www.999精品视频观看免费|