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

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

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


    路慢慢其休遠兮,吾將上下而求素
    posts - 17,comments - 7,trackbacks - 0
    當您自以為已經了解了所有開發工具時,肯定又會冒出一個新的工具。在本文中,developerWorks 的固定撰稿人 Rick Hightower 用一個真實世界的例子向您介紹兩個最激動人心的企業新技術。Hibernate 是一個對象關系映射工具,而 Spring 是一個 AOP 框架和 IOC 容器。Rick 介紹了如何結合這兩者,為企業應用程序構建一個事務持久層。

      如果關心開發人員的最新熱點,那么您可能聽說過 IOC (控制倒置,Inversion of Control)容器和 AOP (面向方面編程)。不過,像許多開發人員一樣,您可能不清楚在自己的開發工作中如何使用這些技術。在本文中,通過具體介紹使用 Hibernate 和 Spring 在企業應用程序中構建一個事務持久層,您會認識到這些技術。

      Hibernate 是 Java 平臺上的一種流行的、容易使用的開放源代碼對象關系(OR)映射框架。Spring 是一個 AOP 框架和 IOC 容器。這兩種技術一起提供了本文中介紹的開發工作的基礎。將使用 Hibernate 把一些持久性對象映射到關系數據庫中,用 Spring 使 Hibernate 更容易使用并提供聲明性事務支持。由于為示例類編寫測試代碼時使用了 DbUnit,我還附帶介紹了一點 TDD (測試驅動的開發)的內容。

      注意,本文假定讀者熟悉 Java 平臺上的企業開發,包括 JDBC、OR 映射內容、J2EE 設計模式如 DAO,以及聲明性事務支持,如 Enterprise JavaBean (EJB)技術所提供的事務支持。理解這里的討論不需要成為這些技術的專家,也不需要熟悉 AOP、IOC 或者 TDD,因為在本文中對這三者都做了介紹。

      我將首先介紹兩種開發技術,然后分析例子。

      Hibernate 簡介

      Hibernate 是 Java 平臺上的一種全功能的、開放源代碼 OR 映射框架。Hibernate 在許多方面類似于 EJB CMP CMR (容器管理的持久性/容器管理的關系)和 JDO(Java Data Objects)。與 JDO 不同,Hibernate 完全著眼于關系數據庫的 OR 映射,并且包括比大多數商業產品更多的功能。大多數 EJB CMP CMR 解決方案使用代碼生成實現持久性代碼,而 JDO 使用字節碼修飾。與之相反,Hibernate 使用反射和運行時字節碼生成,使它對于最終用戶幾乎是透明的(以前 Hibernate 的實現只使用反射,它有助于調試,當前版本保留了這種選項)。

      移植基于 Hibernate 的應用程序

      如果應用程序必須在多個 RDBMS 系統上運行 ,那么基于 Hibernate 的應用程序可以毫不費力地移植到 IBM DB2、MySQL、PostgreSQL、Sybase、Oracle、HypersonicSQL 和許多其他數據庫。我最近甚至將一個應用程序從 MySQL 移植到 Hibernate 沒有很好支持的 Firebird,而這種移植是很容易的。
    Hibernate 可以模擬繼承(有幾種方式)、關聯(一對一或者一對多、containment 和 aggregation)和 composition。我將在本文中討論每種關系類型的幾個例子。

      Hibernate 提供了一種稱為 Hibernate Query Language (HQL) 的 查詢語言,它類似于 JDO 的 JDOQL 和 EJB 的 EJB QL,盡管它更接近于前者。但是 Hibernate 沒有就此止步:它還可以進行直接的 SQL 查詢和/或使用 object criteria 很容易地在運行時構成查詢條件。在本文的例子中我將只使用 HQL。

      與 EJB CMP CMR 不同,Hibernate 像 JDO 一樣可以在 J2EE 容器內部或者外部工作,這可以讓那些進行 TDD 和敏捷開發的人受益。

      Spring 簡介

      AOP 專家 Nicholas Lesiecki 第一次向我解釋 AOP 時,他說的我一個詞也沒理解,我覺得就像第一次考慮使用 IOC 容器的可能性時一樣。每一種技術的概念基礎本身就需要很好地消化,每一種技術所使用的各種各樣的縮寫讓事情更糟了——特別是其中許多術語與我們已經使用的根本不一樣了。

      像許多技術一樣,理解這兩種技術的實際使用比學習理論更容易。經過自己對 AOP 和 IOC 容器實現(即 XWork、PicoContainer 和 Spring)的分析,我發現這些技術可以幫助我獲得功能,而不會在多框架中添加基于代碼的依賴性。它們都將成為我后面開發項目的一部分。

      簡單地說,AOP 讓開發人員可以創建非行為性的關注點,稱為橫切關注點,并將它們插入到應用程序代碼中。使用 AOP 后,公共服務(比如日志、持久性、事務等)就可以分解成方面并應用到域對象上,同時不會增加域對象的對象模型的復雜性。

      IOC 允許創建一個可以構造對象的應用環境,然后向這些對象傳遞它們的協作對象。正如單詞 倒置 所表明的,IOC 就像反過來的 JNDI。沒有使用一堆抽象工廠、服務定位器、單元素(singleton)和直接構造(straight construction),每一個對象都是用其協作對象構造的。因此是由容器管理協作對象(collaborator)。

      Spring 既是一個 AOP 框架、也是一個 IOC 容器。我記得 Grady Booch 說過,對象最好的地方是可以替換它們,而 Spring 最好的地方是它有助于您替換它們。有了 Spring,只要用 JavaBean 屬性和配置文件加入依賴性(協作對象)。然后可以很容易地在需要時替換具有類似接口的協作對象。

      Spring 為 IOC 容器和 AOP 提供了很好的入口(on-ramp)。因此,不需要熟悉 AOP 就可以理解本文中的例子。所需要知道的就是將要用 AOP 為示例應用程序聲明式地添加事務支持,與使用 EJB 技術時的方式基本相同。

      具體到業務

      在本文的其余部分,所有的討論都將基于一個實際的例子。起點是一個企業應用程序,要為它實現一個事務持久層。持久層是一個對象關系數據庫,它包括像 User、User Group、Roles 和 ContactInfo 這些熟悉的抽象。

      在深入到數據庫的要素——查詢和事務管理——之前,需要建立它的基礎:對象關系映射。我將用 Hibernate 設置它,并只使用一點 Spring。

      用 Hibernate 進行 OR 映射

      Hibernate 使用 XML (*.hbm.xml) 文件將 Java 類映射到表,將 JavaBean 屬性映射到數據庫表。幸運的是,有一組 XDoclet 標簽支持 Hibernate 開發,這使得創建所需要的 *.hbm.xml 文件更容易了。清單 1 中的代碼將一個 Java 類映射到數據庫表。

      清單 1. 將 Java 類映射到 DB 表
      [User.java]

    /**
     * @hibernate.class table="TBL_USER"
     * ..
     * ..
     * ...
     */
    public class User {

     private Long id = new Long(-1);
     private String email;
     private String password;
     
     .
     .
     .

     /**
      * @return
      * @hibernate.id column="PK_USER_ID"
      * unsaved-value="-1"
      * generator-class="native" 
      */
     public Long getId() {
      return id;
     }

     ...

     /**
      * @hibernate.property column="VC_EMAIL"
      * type="string"
      * update="false"
      * insert="true"
      * unique="true"
      * not-null="true"
      * length="82"
      * @return
      */
     public String getEmail() {
      return email;
     }

     /**
      * @hibernate.property column="VC_PASSWORD"
      * type="string"
      * update="false"
      * insert="true"
      * unique="true"
      * not-null="true"
      * length="20"
      * @return
      */
     public String getPassword() {
      return password;
     }

     ...
     ...
     ...
    }

      可以看到,@hibernate.class table="TBL_USER" 標簽將 User 映射到 TBL_USER 表。@hibernate.property column="VC_PASSWORD" 將 JavaBean 屬性 password 映射到 VC_PASSWORD 列。@hibernate.id column="PK_USER_ID" 標簽聲明id 屬性是主鍵,它將使用本機(generator-class="native")數據庫機制生成鍵(例如,Oracle sequences 和 SQL Server Identity 鍵)。Hibernate 可以指定 generator-class="native" 以外的、其他可以想象的得到主鍵獲得策略,不過我更愿意使用 native。type 和 length 屬性用于從 Hibernate *.hbm.xml OR 映射文件生成表。這些 final 屬性是可選的,因為使用的可能不是 green-field 數據庫。在這個例子中,已經有數據庫了,所以不需要額外的屬性。(green-field 應用程序 是一個新的應用程序, green-field 數據 是新應用程序的一個新數據庫。不會經常開發一個全新的應用程序,不過偶爾有一兩次也不錯)。

      看過了表如何映射到類以及列如何映射到 JavaBean 屬性,該使用 Hibernate 在 OR 數據庫中設置一些關系了。

      設置對象關系

      在本節中,我將只觸及 Hibernate 提供的設置對象間關系的選項的一小部分。首先設置像 User、User Group、Roles 和 ContactInfo 這些類之間的關系。其中一些關系如圖 1 所示,這是數據庫的驗證對象模型。


    圖 1. 關系的圖示

      如您所見,在上述抽象中存在各種各樣的關系。User 與 ContactInfo 有一對一關系。ContactInfo 的生命周期與 User 相同(用數據庫的術語,UML 中的組成 aka 級聯刪除)。如果刪除 User,則相應的 ContactInfo 也會刪除。在 Users 與 Roles 之間存在多對多關系(即與獨立生命周期相關聯)。在 Groups 與 Users 之間存在一對多關系,因為組有許多用戶。用戶可以存在于組外,即是 aggregation 而不是 composition (用數據庫的說法,在 Groups 和 Users 之間沒有級聯刪除關系)。此外,User 和 Employee 有子類關系,就是說,Employee 的類型為 User。表 1 顯示了如何用 XDoclet 標簽創建一些不同類型的對象關系。

    表 1. 用 XDoclet 創建對象關系
    關系 Java/XDoclet SQL DDL(由 Hibernate Schema Export 生成的 MySQL)
    組包含用戶
    一對多
    Aggregation
    雙向
    (Group<-->Users)
    [Group.java]
    /**
    *
    * @return
    *
    * @hibernate.bag name="users"
    * cascade="save-update"
    * lazy="true"
    * inverse="true"
    *
    * @hibernate.collection-key
    * column="FK_GROUP_ID"
    *
    * @hibernate.collection-one-to-many
    * class="net.sf.hibernateExamples.User"
    */
    public List getUsers() {
    return users;
    }

    [User.java]
    /**
    * @hibernate.many-to-one
    * column="FK_GROUP_ID"
    * class="net.sf.hibernateExamples.Group"
    */
    public Group getGroup() {
    return group;
    }

    create table TBL_USER (
    PK_USER_ID BIGINT NOT NULL AUTO_INCREMENT,
    USER_TYPE VARCHAR(255) not null,
    FK_GROUP_ID BIGINT,
    VC_EMAIL VARCHAR(82) not null unique,
    primary key (PK_USER_ID)
    )


    create table TBL_GROUP (
    PK_GROUP_ID BIGINT NOT NULL AUTO_INCREMENT,
    VC_DESCRIPTION VARCHAR(255),
    VC_NAME VARCHAR(40) unique,
    primary key (PK_GROUP_ID)
    )

    alter table TBL_USER add index (FK_GROUP_ID),
    add constraint FK_111 foreign key (FK_GROUP_ID)
    references TBL_GROUP (PK_GROUP_ID)

    用戶有聯系信息
    一對一
    Composition
    單向
    (User-->ContactInfo)
    [User.java]
    /**
    * @return
    *
    * @hibernate.one-to-one cascade="all"
    *
    */
    public ContactInfo getContactInfo() {
    return contactInfo;
    }

    [ContactInfo.java]
    (Nothing to see here. Unidirectional!)

    create table TBL_USER (
    PK_USER_ID BIGINT NOT NULL AUTO_INCREMENT,
    USER_TYPE VARCHAR(255) not null,
    FK_GROUP_ID BIGINT,
    VC_EMAIL VARCHAR(82) not null unique,
    primary key (PK_USER_ID)
    )

    create table TBL_CONTACT_INFO (
    PK_CONTACT_INFO_ID BIGINT not null,
    ...
    ...
    ...
    primary key (PK_CONTACT_INFO_ID)
    )

    用戶與角色關聯
    多對多
    Association
    單向
    (Users-->Roles)
    [User.java]
    /**
    * @return
    * @hibernate.bag
    * table="TBL_JOIN_USER_ROLE"
    * cascade="all"
    * inverse="true"
    *
    * @hibernate.collection-key
    * column="FK_USER_ID"
    *
    * @hibernate.collection-many-to-many
    * class="net.sf.hibernateExamples.Role"
    * column="FK_ROLE_ID"
    *
    */
    public List getRoles() {
    return roles;
    }

    [Role.java]
    Nothing to see here. Unidirectional!

    create table TBL_ROLE (
    PK_ROLE_ID BIGINT NOT NULL AUTO_INCREMENT,
    VC_DESCRIPTION VARCHAR(200),
    VC_NAME VARCHAR(20),
    primary key (PK_ROLE_ID)
    )

    create table TBL_USER (
    PK_USER_ID BIGINT NOT NULL AUTO_INCREMENT,
    USER_TYPE VARCHAR(255) not null,
    FK_GROUP_ID BIGINT,
    VC_EMAIL VARCHAR(82) not null unique,
    primary key (PK_USER_ID)
    )

    create table TBL_JOIN_USER_ROLE (
    FK_USER_ID BIGINT not null,
    FK_ROLE_ID BIGINT not null
    )

    雇員是用戶
    Inheritance
    用戶
    雇員
    [User.java]
    /**
    * @hibernate.class table="TBL_USER"
    * discriminator-value="2"
    * @hibernate.discriminator column="USER_TYPE"
    *
    ...
    ...
    ...
    */
    public class User {

    [Employee.java]
    /**
    * @hibernate.subclass discriminator-value = "1"
    */
    public class Employee extends User{

    create table TBL_USER (
    PK_USER_ID BIGINT NOT NULL AUTO_INCREMENT,
    USER_TYPE VARCHAR(255) not null,
    FK_GROUP_ID BIGINT,
    VC_EMAIL VARCHAR(82) not null unique,
    primary key (PK_USER_ID)
    )

      Hibernate 中的查詢

      Hibernate 有三種類型的查詢:

      ☆ Criteria, object composition
      ☆ SQL
      ☆ HQL

      在下面的例子中將只使用 HQL。本節還要使用 Spring,用它的 AOP-driven HibernateTemplate 簡化 Hibernate 會話的處理。在本節將開發一個 DAO(Data Access Object)。要了解更多關于 DAO 的內容,請參閱 參考資料。

      清單 2 展示了兩個方法:一個使用 HQL 查詢的組查詢,另一個是后面接一個操作的組查詢。注意在第二個方法中,Spring HibernateTemplate 是如何簡化會話管理的。

      清單 2. 使用查詢

    import net.sf.hibernate.HibernateException;
    import net.sf.hibernate.Session;
    import net.sf.hibernate.Query;
    import org.springframework.orm.hibernate.HibernateCallback;
    import org.springframework.orm.hibernate.support.HibernateDaoSupport;

    /**
     * @author Richard Hightower
     * ArcMind Inc. http://www.arc-mind.com
     */
    public class UserDAO extends HibernateDaoSupport{

      .
      .
      .

      /**
     * Demonstrates looking up a group with a HQL query
     * @param email
     * @return
     */ 
     public Group findGroupByName(String name) {
        return (Group) getHibernateTemplate().find("from Group g where g.name=?",name).get(0);
     }
     
     /**
      * Demonstrates looking up a group and forcing it to populate users (relationship was lazy)
      * @param email
      * @return
      */ 
     public Group findPopulatedGroupByName(final String name) {
        HibernateCallback callback = new HibernateCallback(){

         public Object doInHibernate(Session session) throws HibernateException, SQLException {
       Group group =null;
       String query = "from Group g where g.name=?";
       Query queryObject = getHibernateTemplate().createQuery(session, query);
       queryObject.setParameter(0, name);
       group = (Group) queryObject.list().get(0);
       group.getUsers().size();//force load
       return group;
       }
       
      };
      
      return (Group) getHibernateTemplate().execute(callback);
     }
      .
      .
      .
    }   

      您可能會注意到第二個方法比第一個方法復雜得多,因為它強迫加載 users 集合。因為 Group->Users 之間的關系設置為 lazy initialize(即表 2 中 lazy="true"),組對象需要一個活躍的會話以查詢用戶。在定義 Group 和 Users 之間關系時設置這個屬性為 lazy="false",則不需要第二個方法。在這種情況下,可能使用第一種方法 (findGroupByName) 列出組,用第二種方法(findPopulatedGroupByName)查看組細節。

      Spring IOC 和 Hibernate

      使用 Spring 時,在 J2EE 容器內和容器外工作一樣容易。比如在最近的項目中,我在 Eclipse 中,使用 HSQL 和本地數據庫對使用 Hibernate 事務管理器的 Hypersonic SQL 數據庫進行持久性單元測試。然后,在部署到 J2EE 服務器時,將持久層轉換為使用 J2EE 數據源(通過 JNDI)、JTA 事務和使用 FireBird (一個開放源代碼版本的 Interbase)。這是用 Spring 作為 IOC 容器完成的。

      從清單 3 中可以看出,Spring 允許加入依賴性。注意清單中應用程序上下文文件是如何配置 dataSource 的。dataSource 傳遞給 sessionFactory,sessionFactory 傳遞給 UserDAO。

      清單 3. Spring IOC 和 Hibernate

    <beans>

     <!-- Datasource that works in any application server
      You could easily use J2EE data source instead if this were
      running inside of a J2EE container.
      -->
     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
      <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
      <property name="url"><value>jdbc:mysql://localhost:3306/mysql</value></property>
      <property name="username"><value>root</value></property>
      <property name="password"><value></value></property>
     </bean>

     <!-- Hibernate SessionFactory -->
     <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
      <property name="dataSource"><ref local="dataSource"/></property>
      
      <!-- Must references all OR mapping files. -->
      <property name="mappingResources">
       <list>
              <value>net/sf/hibernateExamples/User.hbm.xml</value>
              <value>net/sf/hibernateExamples/Group.hbm.xml</value>
              <value>net/sf/hibernateExamples/Role.hbm.xml</value>         
              <value>net/sf/hibernateExamples/ContactInfo.hbm.xml</value>
       </list>
      </property>
      
      <!-- Set the type of database; changing this one property will port this to Oracle,
        MS SQL etc. -->
      <property name="hibernateProperties">
       <props>
         <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
       </props>
      </property>
     </bean>
     
     <!-- Pass the session factory to our UserDAO -->
     <bean id="userDAO" class="net.sf.hibernateExamples.UserDAO">
      <property name="sessionFactory"><ref local="sessionFactory"/></property>
     </bean>
     
    </beans>   

      設置了 UserDAO 后,下一步就是定義并使用更多的查詢以展示可以完成的操作。Hibernate 可以用預定義查詢將查詢存儲到源代碼之外,如清單 4 所示。

      清單 4. 預定義查詢
      [User.java]

    /**
     * @author Richard Hightower
     * ArcMind Inc. http://www.arc-mind.com
     * @hibernate.class table="TBL_USER" discriminator-value="2"
     * @hibernate.discriminator column="USER_TYPE"
     *
     * @hibernate.query name="AllUsers" query="from User user order by user.email asc"
     *
     * @hibernate.query name="OverheadStaff"
     * query="from Employee employee join employee.group g where g.name not in ('ENGINEERING','IT')"
     *
     * @hibernate.query name="CriticalStaff"
     * query="from Employee employee join employee.group g where g.name in ('ENGINEERING','IT')"
     *
     * @hibernate.query name="GetUsersInAGroup"
     * query="select user from Group g join g.users user"
     *
     * @hibernate.query name="GetUsersNotInAGroup"
     * query="select user from User user where user.group is null"
     *
     * @hibernate.query name="UsersBySalaryGreaterThan"
     * query="from User user inner join user.contactInfo info where info.salary > ?1"
     *
     * @hibernate.query name="UsersBySalaryBetween"
     * query="from User user join user.contactInfo info where info.salary between ?1 AND ?2"
     *
     * @hibernate.query name="UsersByLastNameLike"
     * query="from User user join user.contactInfo info where info.lastName like ?1"
     *
     * @hibernate.query name="GetEmailsOfUsers"
     * query="select user.email from Group g join g.users as user where g.name = ?1"
     *
     */
    public class User {
       .
       .
       .   

      上述代碼定義了幾個預定義查詢。預定義查詢 是存儲在 *.hbm.xml 文件中的查詢。在清單 5 中,可以看到如何執行預定義查詢。

      清單 5. 使用預定義查詢
      [UserDAO.java]

     /**
      * Demonstrates a query that returns a String.
      */               
     public String[] getUserEmailsInGroup(String groupName){
      List emailList =
      getHibernateTemplate().findByNamedQuery("GetEmailsOfUsers");
      return (String [])
       emailList.toArray(new String[emailList.size()]);
     }

     /**
      * Demonstrates a query that returns a list of Users
      *
      * @return A list of emails of all of the users in the authentication system.
      *
      */               
     public List getUsers(){
      return getHibernateTemplate().findByNamedQuery("AllUsers");
     }

          /**
     * Demonstrates passing a single argument to a query.
     *
     * @return A list of UserValue objects.
     *
     */                   
     public List getUsersBySalary(float salary){
        return getHibernateTemplate()
            .findByNamedQuery("UsersBySalaryGreaterThan",
                 new Float(salary));
     }

     /**
      * Demonstrates passing multiple arguments to a query
      *
      * @return A list of UserValue objects.
      *
      */                   
     public List getUsersBySalaryRange(float start, float stop){
                    return getHibernateTemplate()
       .findByNamedQuery("UsersBySalaryBetween",
       new Object[] {new Float(start), new Float(stop)});
     }

      查詢進行時,可以在持久層中加上最后一層:使用 Spring 的事務管理。

      用 Spring 管理事務

      Spring 可以聲明式地管理事務。例如,UserDAO.addUser 方法當前不是在單個事務中執行的。因此,組中的每一個用戶都插入到自己的事務中,如清單 6 所示。

      清單 6. 添加一組用戶
      [UserDAO.java]

    /**
     * @param group
     */
    public void addGroup(Group group) {
     getHibernateTemplate().save(group);
     
    }

    [UserDAOTest.java]

    public void testAddGroupOfUsers(){
     Group group = new Group();
     
     for (int index=0; index < 10; index++){
      User user = new User();
      user.setEmail("rick"+index+"@foobar.com" );
      user.setPassword("foobar");
      group.addUser(user); 
     }
     
     group.setName("testGroup");
     
     userDAO.addGroup(group);
     assertNotNull(group.getId());
     
     Group group2 = userDAO.findPopulatedGroupByName("testGroup");
     
     assertEquals("testGroup",group2.getName());
     assertEquals(10, group2.getUsers().size());
     String email = ((User)group2.getUsers().get(0)).getEmail();
     assertEquals("rick0@foobar.com", email);

    }

      不建議使用上述解決方案,因為每一個 User 都要在自己的事務中插入到數據庫中。如果出現問題,那么只能添加部分用戶。如果希望保留 ACID 屬性(即保證所有都發生或者所有都不發生),可以通過程序進行事務管理,但是它很快就會變得一團糟了。相反,應使用 Spring 的 AOP 來支持聲明式的事務,如清單 7 所示。

      清單 7. 聲明式管理事務
      [applicationContext.xml]

    <!-- Pass the session factory to our UserDAO -->
       <bean id="userDAOTarget" class="net.sf.hibernateExamples.UserDAOImpl">
     <property name="sessionFactory"><ref local="sessionFactory"/></property>
       </bean>
     
       <bean id="transactionManager"
        class="org.springframework.orm.hibernate.HibernateTransactionManager">
          <property name="sessionFactory"><ref bean="sessionFactory"/></property>
       </bean>

    <bean id="userDAO"
         class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
     <property name="transactionManager"><ref local="transactionManager"/></property>
     <property name="target"><ref local="userDAOTarget"/></property>
     <property name="transactionAttributes">
      <props>
       <prop key="addGroup">PROPAGATION_REQUIRED</prop>
      </props>
     </property>
    </bean>

      注意在準備清單 7 的代碼時,我重新改寫了 UserDAO 并提取了其接口。這個接口現在是 UserDAO,它的實現類是 UserDAOImpl。這樣清單 7 中的事務代碼就使用了帶有事務屬性 (PROPAGATION_REQUIRED) 的 UserDAO.addGroup() 方法。現在只要底層數據庫支持,就可以在一個事務中添加所有用戶。

      結束語

      在本文中,介紹了如何使用 Hibernate 和 Spring 實現一個事務持久層。Hibernate 是一種先進的 OR 映射工具,而 Spring 是一個 AOP 框架和 IOC 容器。這兩種技術的綜合使用,使得開發人員可以編寫媲美數據庫廠商的代碼,它可以在 J2EE 容器中運行,也可以單獨運行。使用了 DbUnit (JUnit 的擴展)構建和測試本文中例子的所有代碼,雖然這不是討論的重點。

    posted on 2005-07-13 14:31 Steve 閱讀(130) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲AV日韩AV永久无码绿巨人| 免费无码午夜福利片| 亚洲成AV人片在线观看无| 在线观看午夜亚洲一区| 亚洲精品无码永久中文字幕| 久久亚洲精品成人AV| 亚洲一区在线观看视频| 在线观看亚洲电影| 在线观看免费大黄网站| 超清首页国产亚洲丝袜| 亚洲欧洲春色校园另类小说| 亚洲日韩国产一区二区三区在线 | 亚洲一卡一卡二新区无人区| 美女裸体无遮挡免费视频网站| 国产免费高清69式视频在线观看| 久久精品视频免费播放| 成人性生活免费视频| 国产亚洲成av人片在线观看| 精品日韩99亚洲的在线发布 | a毛片成人免费全部播放| 91久久精品国产免费直播| 四虎永久免费网站免费观看| 久久久久亚洲精品美女| 久久人午夜亚洲精品无码区| 久久久久久久岛国免费播放 | 美女被羞羞网站免费下载| 中文永久免费观看网站| www视频在线观看免费| 高清在线亚洲精品国产二区| 亚洲av激情无码专区在线播放| 国产成人亚洲综合网站不卡| 国内精品久久久久影院免费| 成年男女男精品免费视频网站| 亚洲色欲久久久综合网东京热| 亚洲国产成人无码av在线播放| 永久免费无码网站在线观看个 | 午夜成年女人毛片免费观看| 久久久久久A亚洲欧洲AV冫| 亚洲欧洲自拍拍偷综合| 日韩毛片免费一二三| 一个人免费观看在线视频www|