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

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

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

    CreateDAO_zh

    Posted on 2006-07-06 17:53 負(fù)人博客 閱讀(297) 評(píng)論(0)  編輯  收藏 所屬分類: 軟件設(shè)計(jì)

    Part I: &#22312;AppFuse&#24314;&#31435;DAO&#21644;&#23545;&#35937; - 一個(gè)建立對(duì)象(代表數(shù)據(jù)庫(kù)的表)和把這些對(duì)象存儲(chǔ)到數(shù)據(jù)庫(kù)的Java類的教程。

    關(guān)于本教程

    本教程將向你展示如何在一個(gè)數(shù)據(jù)庫(kù)里創(chuàng)建表,以及如何完成訪問(wèn)這些表的Java代碼。

    我們將建立一個(gè)對(duì)象以及處理(保存/檢索/刪除)這些類到數(shù)據(jù)庫(kù)的一些代碼。用Java術(shù)語(yǔ),我們叫它Plain Old Java Object(a.k.a. a POJO)。這個(gè)對(duì)象通常代表了數(shù)據(jù)庫(kù)中的一個(gè)表,其他的類包括:

    • 一個(gè)數(shù)據(jù)訪問(wèn)對(duì)象Data Access Object (a.k.a. a DAO), 一個(gè) Interface和一個(gè)Hibernate實(shí)現(xiàn)
    • 一個(gè) JUnit 類來(lái)測(cè)試我們的DAO對(duì)象
    NOTE: 如果你使用MySQL并且希望使用事務(wù) (很有可能是這個(gè)情況),你需要使用InnoDB tables,為了做到這一點(diǎn), 添加以下兩句話到 (/etc/my.cnf 或者 c:\Windows\my.ini)。 其中第二個(gè)設(shè)置 (設(shè)置使用UTF-8字符)是4.1.7+所必需的。
    [mysqld]
    default-table-type=innodb
    default-character-set=utf8
    
    如果你使用PostgreSQL并且在成批處理時(shí)得到許多迷惑的錯(cuò)誤,試著把關(guān)閉它,方法是增加 <prop key="hibernate.jdbc.batch_size">0</prop> 到你的 src/dao/**/hibernate/applicationContext-hibernate.xml文件。

    AppFuse使用Hibernate 作為持久化層, Hibernate是一套對(duì)象/關(guān)系Object/Relational (O/R)框架,他允許你把Java對(duì)象和數(shù)據(jù)庫(kù)之間聯(lián)系起來(lái),它可以很方便的對(duì)你的對(duì)象執(zhí)行CRUD (Create, Retrieve, Update, Delete)操作。

    你也可以選擇使用iBATIS作為持久化層,如果要在AppFuse里安裝iBATIS, 請(qǐng)查看extras/ibatis中的README.txt。如果你選擇iBATIS而不是Hibernate, 希望你有自己的原因并且熟悉這個(gè)框架,我也希望你能夠領(lǐng)會(huì)到如何將教程應(yīng)用到iBATIS ;-)

    字體慣例 (進(jìn)行中)

    要在命令行下執(zhí)行的命令是這個(gè)樣子: ant test-all.
    對(duì)目錄或者包中的文件的引用是這個(gè)樣子: build.xml.
    我在?真實(shí)世界?中實(shí)際操作的方式用藍(lán)色斜體表示。

    讓我們繼續(xù)在AppFuse項(xiàng)目的結(jié)構(gòu)下創(chuàng)建一個(gè)新的對(duì)象、DAO和測(cè)試。

    目錄

    • [1] 建立一個(gè)對(duì)象,并且作XDoclet標(biāo)記
    • [2] 使用Ant根據(jù)對(duì)象建立數(shù)據(jù)庫(kù)中的表
    • [3] 創(chuàng)建一個(gè)DaoTest來(lái)運(yùn)行DAO對(duì)象的JUnit測(cè)試
    • [4] 創(chuàng)建一個(gè)新的DAO來(lái)執(zhí)行關(guān)于這個(gè)對(duì)象的CRUD操作
    • [5] 在spring里配置Person和PersonDao
    • [6] 運(yùn)行DaoTest

    建立一個(gè)對(duì)象,并且作XDoclet標(biāo)記 [#1]

    我們要做的第一件事情就是建立一個(gè)需要持久化的對(duì)象,我們要在src/dao/**/model目錄下建立一個(gè)簡(jiǎn)單的Person對(duì)象,這個(gè)對(duì)象包括id、firstName和lastName屬性。

    注意: 直接拷貝本教程的代碼 &#22312;FireFox&#19979;&#26080;&#25928;,但我們可以通過(guò)CTRL+Click選定一個(gè)代碼所在的工作區(qū)(OS X下是Command+Click),然后再拷貝。


    package?org.appfuse.model;

    public?class?Person?extends?BaseObject?{
    ????private?Long?id;
    ????private?String?firstName;
    ????private?String?lastName;

    ????/*
    ?????Generate?your?getters?and?setters?using?your?favorite?IDE:?
    ?????In?Eclipse:
    ?????Right-click?->?Source?->?Generate?Getters?and?Setters
    ????*/
    }

    這個(gè)類必須擴(kuò)展BaseObject,而這個(gè)BaseObject有三個(gè)抽象方法(equals(), hashCode()和toString())需要你在Person類里實(shí)現(xiàn),前兩個(gè)是Hibernate的需要。為了完成這部分工作最簡(jiǎn)單的方式是使用Commonclipse,關(guān)于這個(gè)工具更多的信息可以在Lee Grey&#30340;&#32593;&#31449;里看到,另外一個(gè)你可以使用的Eclipse的插件是Commons4E,我還沒(méi)有使用過(guò),這里不便對(duì)其功能作出評(píng)論。

    如果你使用IntelliJ IDEA,你可以自動(dòng)產(chǎn)生equals()和hashCode(),但沒(méi)有toString(),有一個(gè) ToStringPlugin插件做得非常不錯(cuò)

    現(xiàn)在我們已經(jīng)創(chuàng)建了這個(gè)POJO對(duì)象,我們需要增加X(jué)Doclet標(biāo)記來(lái)產(chǎn)生Hibernate的映射文件,這些文件用來(lái)映射對(duì)象→ 表和屬性(變量) → 字段。

    首先,我們?cè)黾?a class="external" >@hibernate.class 來(lái)告訴Hibernate我們將要和那個(gè)表作關(guān)聯(lián):


    /**
    ?*?@hibernate.class?table="person"
    ?*/
    public?class?Person?extends?BaseObject?{

    我們也要增加主鍵的映射,否則XDoclet會(huì)在產(chǎn)生映射文件時(shí)出錯(cuò),注意所有的@hibernate.*標(biāo)簽必須在getters'的Javadocs里面。


    ????/**
    ?????*?@return?Returns?the?id.
    ?????*?@hibernate.id?column="id"
    ?????*??generator-class="increment"?unsaved-value="null"
    ?????*/

    ????public?Long?getId()?{
    ????????return?this.id;
    ????}

    我使用generator-class="increment"而不使用generate-class="native" 是因?yàn)槲覍?duì)數(shù)據(jù)庫(kù)使用"native"時(shí),本教程使用increment。

    使用Ant根據(jù)對(duì)象產(chǎn)生數(shù)據(jù)庫(kù)表[#2]

    在這種情況下,你可以通過(guò)運(yùn)行ant setup-db來(lái)建立person表,這個(gè)任務(wù)會(huì)產(chǎn)生文件Person.hbm.xml并且會(huì)建立叫做"person"的表,從Ant的控制臺(tái)窗口,你可以看到Hibernate為你建立的表結(jié)構(gòu)的內(nèi)容。
    [schemaexport] create table person (
    [schemaexport]    id bigint not null,
    [schemaexport]    primary key (id)
    [schemaexport] );
    

    如果你查看Hibernate生成的文件Person.hbm.xml,可以到build/dao/gen/**/model目錄,這里是Person.hbm.xml的內(nèi)容(目前的內(nèi)容):


    <?xml?version="1.0"?>

    <!DOCTYPE?hibernate-mapping?PUBLIC
    ????"-//Hibernate/Hibernate?Mapping?DTD?2.0//EN"?
    ????"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

    <hibernate-mapping>
    ????<class
    ????????name="org.appfuse.model.Person"
    ????????table="person"
    ????????dynamic-update="false"
    ????????dynamic-insert="false"
    ????>

    ????????<id
    ????????????name="id"
    ????????????column="id"
    ????????????type="java.lang.Long"
    ????????????unsaved-value="null"
    ????????>
    ????????????<generator?class="increment">
    ????????????</generator>
    ????????</id>

    ????????<!--
    ????????????To?add?non?XDoclet?property?mappings,?create?a?file?named
    ????????????????hibernate-properties-Person.xml
    ????????????containing?the?additional?properties?and?place?it?in?your?merge?dir.
    ????????-->

    ????</class>

    </hibernate-mapping>

    現(xiàn)在我們要為其它的字段(first_name, last_name)添加額外的@hibernate.property標(biāo)簽:


    ????/**
    ?????*?@hibernate.property?column="first_name"?length="50"
    ?????*/
    ????public?String?getFirstName()?{
    ????????return?this.firstName;
    ????}

    ????/**
    ?????*?@hibernate.property?column="last_name"?length="50"
    ?????*/
    ????public?String?getLastName()?{
    ????????return?this.lastName;
    ????}

    在這個(gè)例子里,添加column屬性的唯一原因是因?yàn)檫@個(gè)字段名與它的屬性名不相同,如果他們相同,你沒(méi)有必要來(lái)指定column屬性,關(guān)于其它可以使用的標(biāo)簽請(qǐng)看@hibernate.property

    再次運(yùn)行ant setup-db把新加的屬性加到數(shù)據(jù)庫(kù)表里。

    [schemaexport] create table person (
    [schemaexport]    id bigint not null,
    [schemaexport]    first_name varchar(50),
    [schemaexport]    last_name varchar(50),
    [schemaexport]    primary key (id)
    [schemaexport] );

    如果期望修改字段的長(zhǎng)度,修改@hibernate.property標(biāo)簽的length屬性,如果希望把字段改為必添字段(NOT NULL),可以增加屬性not-null="true"。

    建立新的DaoTest來(lái)對(duì)你的DAO運(yùn)行JUnit測(cè)試[#3]

    注意:從Appfuse版本1.6.1+開(kāi)始包括了一個(gè)AppGen工具,可以用來(lái)生成本教程余下的所有的類的代碼,不過(guò),我們最好還是先過(guò)一遍教程再使用這個(gè)工具產(chǎn)生代碼。

    現(xiàn)在,我們要?jiǎng)?chuàng)建一個(gè)DaoTest來(lái)測(cè)試我們的DAO的工作,?等會(huì)兒?,你說(shuō),?我們還不曾創(chuàng)建DAO呢!?,你說(shuō)得對(duì)。無(wú)論如何,我發(fā)現(xiàn)&#27979;&#35797;&#39537;&#21160;&#24320;&#21457;大大的促進(jìn)了軟件質(zhì)量,在許多年里我一直認(rèn)為在寫(xiě)代碼之前寫(xiě)測(cè)試是胡說(shuō)八道,這看起來(lái)很愚蠢,但當(dāng)我嘗試之后我認(rèn)為這樣非常好,現(xiàn)在我按照測(cè)試驅(qū)動(dòng)的方式工作完全因?yàn)槲野l(fā)現(xiàn)這樣可以大大提高我軟件開(kāi)發(fā)的效率。

    開(kāi)始,我們?cè)?tt>test/dao/**/dao目錄下建立類PersonDaoTest.java,這個(gè)類必須擴(kuò)展BaseDaoTestCase,而B(niǎo)aseDAOTestCase這個(gè)類是JUnit類TestCase的子類,這個(gè)類用來(lái)加載Spring的ApplicationContext(因?yàn)镾pring把各個(gè)層綁定)和單元測(cè)試類同一目錄下同你的測(cè)試類文件同名的.properties文件(ResourceBundle),這個(gè)屬性文件的屬性可以通過(guò)?rb?屬性來(lái)訪問(wèn)。

    我經(jīng)常拷貝(打開(kāi)→另存為)一個(gè)已存在的測(cè)試(如UserDaoTest.java),然后查找/替換 [Uu]ser為[Pp]erson,或者任何其它需要替換的內(nèi)容。


    package?org.appfuse.dao;

    import?org.appfuse.model.Person;
    import?org.springframework.dao.DataAccessException;

    public?class?PersonDaoTest?extends?BaseDaoTestCase?{
    ????
    ????private?Person?person?=?null;
    ????private?PersonDao?dao?=?null;

    ????public?void?setPersonDao(PersonDao?dao)?{
    ????????this.dao?=?dao;
    ????}
    }

    以上是我們使用JUnit測(cè)試而初始化和銷毀PersonDao的基本代碼,對(duì)象?ctx?引用了Spring的ApplicationContext,它在BaseDaoTestCase類的靜態(tài)代碼區(qū)里被初始化。

    現(xiàn)在我們需要實(shí)際測(cè)試DAO中的CRUD(create, retrieve, update, delete)方法,為此我們需要為每個(gè)方法建立以test(全部小寫(xiě))開(kāi)頭的測(cè)試方法,只要這個(gè)方法是公共的,返回類型是void,它們就會(huì)被我們build.xml中的Ant的<junit>任務(wù)調(diào)用,如下是一些簡(jiǎn)單的CRUD測(cè)試,需要注意的一點(diǎn)是所有的方法(或者叫做測(cè)試)必須是自治的,添加如下代碼到文件PersonDaoTest.java


    ????public?void?testGetPerson()?throws?Exception?{
    ????????person?=?new?Person();
    ????????person.setFirstName("Matt");
    ????????person.setLastName("Raible");

    ????????dao.savePerson(person);
    ????????assertNotNull(person.getId());

    ????????person?=?dao.getPerson(person.getId());
    ????????assertEquals(person.getFirstName(),?"Matt");
    ????}

    ????public?void?testSavePerson()?throws?Exception?{
    ????????person?=?dao.getPerson(new?Long(1));
    ????????person.setFirstName("Matt");

    ????????person.setLastName("Last?Name?Updated");

    ????????dao.savePerson(person);

    ????????if?(log.isDebugEnabled())?{
    ????????????log.debug("updated?Person:?"?+?person);
    ????????}

    ????????assertEquals(person.getLastName(),?"Last?Name?Updated");
    ????}

    ????public?void?testAddAndRemovePerson()?throws?Exception?{
    ????????person?=?new?Person();
    ????????person.setFirstName("Bill");
    ????????person.setLastName("Joy");

    ????????dao.savePerson(person);

    ????????assertEquals(person.getFirstName(),?"Bill");
    ????????assertNotNull(person.getId());

    ????????if?(log.isDebugEnabled())?{
    ????????????log.debug("removing?person...");
    ????????}

    ????????dao.removePerson(person.getId());

    ????????try?{
    ????????????person?=?dao.getPerson(person.getId());
    ????????????fail("Person?found?in?database");
    ????????}?catch?(DataAccessException?dae)?{
    ????????????log.debug("Expected?exception:?"?+?dae.getMessage());
    ????????????assertNotNull(dae);
    ????????}
    ????}

    在testGetPerson方法,我們創(chuàng)建了一個(gè)person并且調(diào)用get方法,我通常會(huì)增加一條我所需要的記錄到數(shù)據(jù)庫(kù),因?yàn)樵跍y(cè)試運(yùn)行之前DBUnit會(huì)為數(shù)據(jù)庫(kù)準(zhǔn)備測(cè)試數(shù)據(jù),我們可以簡(jiǎn)單的在metadata/sql/sample-data.xml里添加測(cè)試所必須的記錄

    <table name='person'>
        <column>id</column>
        <column>first_name</column>
        <column>last_name</column>
        <row>
          <value>1</value>
          <value>Matt</value>
          <value>Raible</value>
        </row>
    </table>
    
    通過(guò)這種方式你可以在testGetPerson方法里消除創(chuàng)建新紀(jì)錄的動(dòng)作,如果你愿意直接插入記錄到數(shù)據(jù)庫(kù)(使用SQL或者GUI),你可以用ant db-exportcp db-export.xml metadata/sql/sample-data.xml重新構(gòu)建你的sample-data.xml文件。

    在上面的例子里,你可以看到我們調(diào)用person.set*(value)來(lái)準(zhǔn)備我們需要保存的對(duì)象,在這個(gè)例子里很簡(jiǎn)單,但是當(dāng)你要插入10條必添字段(not-null="true")時(shí)就比較麻煩了,這就是我為什么要在BaseDaoTestCase使用ResourceBundle文件,只要在PersonDaoTest.java同一個(gè)目錄創(chuàng)建一個(gè)PersonDaoTest.properties并且在里面定義你的屬性值:

    我通常只是在Java里硬編碼,但是這個(gè).properties對(duì)于大對(duì)象很有用。
    firstName=Matt
    lastName=Raible
    
    此時(shí),你要通過(guò)調(diào)用BaseDaoTestCase.populate(java.lang.Object)方法來(lái)準(zhǔn)備對(duì)象,而不是使用person.set*。


    person?=?new?Person();
    person?=?(Person)?populate(person);

    在目前情況下,還不可以編譯PersonDaoTest,因?yàn)樵陬惵窂嚼镞€沒(méi)有PersonDao.class,我們需要?jiǎng)?chuàng)建它。PersonDao.java是一個(gè)接口,PersonDaoHibernate.java是它的Hibernate實(shí)現(xiàn),讓我們繼續(xù),開(kāi)始創(chuàng)建。

    創(chuàng)建一個(gè)對(duì)對(duì)象執(zhí)行CRUD操作的新DAO[#4]

    馬上,在src/dao/**/dao目錄里建立PersonDao.java接口,并且指定所有實(shí)現(xiàn)類要實(shí)現(xiàn)的基本CRUD操作,為了顯示方便,我已經(jīng)去掉了所有JavaDocs。


    package?org.appfuse.dao;

    import?org.appfuse.model.Person;

    public?interface?PersonDao?extends?Dao?{
    ????public?Person?getPerson(Long?personId);
    ????public?void?savePerson(Person?person);
    ????public?void?removePerson(Long?personId);
    }

    注意,在以上的方法聲明上并沒(méi)有exceptions說(shuō)明,這是因?yàn)?a class="external" >Spring使用RuntimeExceptions來(lái)包裹Exceptions的方式,此時(shí),你已經(jīng)可以使用ant compile-dao來(lái)編譯src/daotest/dao下的所有源文件,然而當(dāng)你運(yùn)行ant test-dao -Dtestcase=PersonDao進(jìn)行測(cè)試時(shí),你會(huì)得到一個(gè)錯(cuò)誤:No bean named 'personDao' is defined,這是一個(gè)Spring的錯(cuò)誤,說(shuō)明你必須在applicationContext-hibernate.xml指定一個(gè)名字為personDAO的bean,在此之前我們需要?jiǎng)?chuàng)建PersonDao的實(shí)現(xiàn)類。

    運(yùn)行dao測(cè)試的ant任務(wù)叫做test-dao,如果你傳遞testcase參數(shù)(用-Dtestcase=name),它會(huì)查看**/*${testcase}*允許我們傳遞Person、PersonDao、或者PersonDaoTest以及所有會(huì)執(zhí)行PersonDaoTest的類。

    讓我們創(chuàng)建一個(gè)實(shí)現(xiàn)PersonDao的類PersonDaoHibernate并使用Hibernate來(lái)get/save/delete這個(gè)Person對(duì)象,為此,我們?cè)?tt>src/dao/**/dao/hibernate創(chuàng)建一個(gè)新類PersonDaoHibernate.java,它應(yīng)該擴(kuò)展BaseDaoHibernate,并且實(shí)現(xiàn)PersonDao。為了簡(jiǎn)潔,省略Javadocs。


    package?org.appfuse.dao.hibernate;

    import?org.appfuse.model.Person;
    import?org.appfuse.dao.PersonDao;
    import?org.springframework.orm.ObjectRetrievalFailureException;

    public?class?PersonDaoHibernate?extends?BaseDaoHibernate?implements?PersonDao?{

    ????public?Person?getPerson(Long?id)?{
    ????????Person?person?=?(Person)?getHibernateTemplate().get(Person.class,?id);

    ????????if?(person?==?null)?{
    ????????????throw?new?ObjectRetrievalFailureException(Person.class,?id);???
    ????????}

    ????????return?person;
    ????}

    ????public?void?savePerson(Person?person)?{
    ????????getHibernateTemplate().saveOrUpdate(person);
    ????}

    ????public?void?removePerson(Long?id)?{
    ????????//?object?must?be?loaded?before?it?can?be?deleted
    ????????getHibernateTemplate().delete(getPerson(id));
    ????}
    }

    現(xiàn)在,如果你運(yùn)行ant test-dao -Dtestcase=PersonDao,你會(huì)得到同樣的錯(cuò)誤,我們必須配置Spring來(lái)讓它知道PersonDaoHibernate是PersonDao的實(shí)現(xiàn),同樣的,我們也要告訴它還有個(gè)Person對(duì)象。

    配置Spring中的Person和PersonDao [#5]

    首先我們要告訴Spring所有Hibernate文件的位置,為此,打開(kāi)src/dao/**/dao/hibernate/applicationContext-hibernate.xml,在以下代碼塊添加"Person.hbm.xml"


    <property?name="mappingResources">?
    ????<list>?
    ????????<value>org/appfuse/model/Person.hbm.xml</value>?
    ????????<value>org/appfuse/model/Role.hbm.xml</value>?
    ????????<value>org/appfuse/model/User.hbm.xml</value>
    ????</list>?
    </property>?

    現(xiàn)在我們需要添加一些XML數(shù)據(jù)來(lái)綁定PersonDaoHibernate到PersonDao,為此,添加如下代碼到文件底部:


    <!--?PersonDao:?Hibernate?implementation?-->?
    <bean?id="personDao"?class="org.appfuse.dao.hibernate.PersonDaoHibernate">?
    ????<property?name="sessionFactory"><ref?local="sessionFactory"/></property>?
    </bean>?

    你也可以為<bean>使用autowire="byName"屬性來(lái)消除"sessionFactory"屬性從個(gè)人來(lái)講,我喜歡在XML文件里保留對(duì)象的依賴。

    運(yùn)行DaoTest[#6]

    保存所有修改的文件,運(yùn)行ant test-dao -Dtestcase=PersonDao

    Yeah Baby, Yeah:BUILD SUCCESSFUL
    Total time: 9 seconds


    下一部分:Part II:&#21019;&#24314;&#31649;&#29702;&#22120;Manager - 是一個(gè)建立類似于Session Facades的,但不使用EJBs的業(yè)務(wù)Facade說(shuō)明,這個(gè)facades用來(lái)建立從前端到DAO層的聯(lián)系。


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     

    posts - 26, comments - 5, trackbacks - 0, articles - 8

    Copyright © 負(fù)人博客

    主站蜘蛛池模板: 亚洲看片无码在线视频| 久久久久亚洲AV综合波多野结衣 | 久久久久久亚洲精品成人| 亚洲AV永久无码精品| 亚洲av综合av一区| 亚洲天堂男人天堂| 亚洲视频一区在线| 91嫩草亚洲精品| 亚洲一卡2卡三卡4卡无卡下载| 亚洲 欧洲 视频 伦小说| 国产亚洲中文日本不卡二区| 亚洲熟妇成人精品一区| 羞羞视频免费网站入口| 四虎影视久久久免费观看| 你懂得的在线观看免费视频| 久久精品一区二区免费看| **实干一级毛片aa免费| 日韩版码免费福利视频| 国产成人免费a在线视频app| 亚洲色偷偷狠狠综合网| 亚洲av无码专区国产乱码在线观看| 亚洲va久久久噜噜噜久久男同| 亚洲精品在线电影| 中文字幕亚洲精品无码| 老司机精品视频免费| 久久精品免费大片国产大片| 久久99青青精品免费观看| 国产曰批免费视频播放免费s| 国产乱码免费卡1卡二卡3卡| 日韩一区二区在线免费观看| 亚洲欧洲日本在线| 亚洲精品国产电影午夜| 色五月五月丁香亚洲综合网| 9久久免费国产精品特黄| 亚洲网站免费观看| 国产精品色午夜免费视频| 亚洲色自偷自拍另类小说| 亚洲综合免费视频| 激情婷婷成人亚洲综合| 色播在线永久免费视频网站| 毛片免费观看网址|