新的起點 新的開始

          快樂生活 !

          JPA 設計模式系列一 DAO Pattern in JPA

                   作為JavaEE5 規范一部分的JPA,已經有眾多的實現,比如:Hiberante,TopLink, EclipseLink和OpenJPA 等許多ORM框架。JPA不僅僅應用于EJB3中,你也可以應用EJB3之外的應用,比如Spring 中。甚至Gavin King Hiberante的作者 在Hiberante in Action 的第二版書中也推薦使用JPA。很明顯,JPA將被廣泛的應用。

                  
          一旦你熟悉annotation,并嘗試過Hello world之類的程序后,你會感覺,恩 JPA確實不錯。然后,當你在你的項目中開始應用JPA時,你會發現其實并不那么簡單,你需要考慮如何處理事務,惰性加載,移除對象實例, 繼承等等。這些問題會在本系列中給你答案。

                
          首先進入第一的設計模式 DAO。


           我們需要DAO嗎?

                 
          在二年前,我們已經討論了這個問題了,討論的結果是:是否使用DAO依賴于你的應用,類似于GOF的設計模式,如果是很簡單的應用程序,應用設計模式,只能增加你的復雜度。 而對于復雜應用程序,正因為其復雜,應用設計模式可以減低復雜度,提高可維護性。 

                 
          應用了DAO我們可以得到如下好處:

                 1. 
          避免在任何存取數據的代碼中引入EntityManager,減少了依賴。

                 2. 
          對某些實體Bean操作增加限制。比如你不想對LogEntry提供刪除操作,應用DAO,你僅僅做的是不要在LogEntry DAO中不要添加remove的方法。

                 3. 
          理論上,應用DAO層,你一個自由切換其他的持久機制比如純JDBC或者Ibatis.而實際上,JPA已經是一個抽象層,這種切 換是沒有意義的。

                4. 
          你可以在一個實體中集中所有的查詢避免這些查詢在其他代碼中出現。你可以使用named queries 在實體類中查詢,但是您仍然需要正確的參數被設置。對應這種查詢,你可以在DAO中設置參數,然后轉換成正確的返回類型,比如:

              
          public List<ChangePlan> findExecutingChangePlans() {

                Query query = entityManager.createQuery(
                      "SELECT plan FROM ChangePlan plan where plan.state = 'EXECUTING'");
                return (List<ChangePlan>) query.getResultList();
          }

          然后,但你決定使用DAO時,如何正確合理的使用它呢? SpringJpaTemplateJavaDoc中建議,不要使用類似特殊的類,類似JpaDaoSupport。 而是你應該自己通過@PersistenceContext注釋獲取EntityManger來維護你的DAO。這種方式可以在EJB3的容器中工作,并且如果你在Springcontext 加入PersistenceAnnotationBeanpostProcessor Bean的話,在Spring2.0里也是沒有問題的。

          類型安全且泛化的DAO pattern

              因為每一個DAO都包含一些相同的邏輯,所以我們應該抽取這些邏輯放入到父類中。

          實體類

          比如,我們想實例化OrderClass

          @Entity
          @Table(name = "ORDERS")
          public class Order {
                  @Id
                  @GeneratedValue
                  private int id;
                  private String customerName;
                  private Date date;
           
                  public int getId() { return id; }
                  public void setId(int id) { this.id = id; }
           
                  public String getCustomerName() { return customerName; }
                  public void setCustomerName(String customerName) { this.customerName = customerName; }
           
                  public Date getDate() { return date; }
                  public void setDate(Date date) { this.date = date;}

          DAO 接口

          首先我們定義一個泛化的DAO接口,包括最常用的方法,比如:

          public interface Dao<K, E> {
                void persist(E entity);
                void remove(E entity);
                E findById(K id);
          }

          K ,E為泛型,你可以加其他的方法比如:List findAll().

          然后我們定義一個自接口,實現特殊的方法,比如,我們想查找一定條件的Order信息:

          public interface OrderDao extends Dao<Integer, Order> {
                  List<Order> findOrdersSubmittedSince(Date date);
          }

          基本DAO的實現

          第三步就是創建基本的JPA DAO的實現。它實現了Dao接口。

          public abstract class JpaDao<K, E> implements Dao<K, E> {
                  protected Class<E> entityClass;
           
                  @PersistenceContext
                  protected EntityManager entityManager;
           
                  public JpaDao() {
                         ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
                         this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1];
                  }
           
                  public void persist(E entity) { entityManager.persist(entity); }
           
                  public void remove(E entity) { entityManager.remove(entity); }
           
                  public E findById(K id) { return entityManager.find(entityClass, id); }

            上述實現是直接明了的,大家還要注意幾點:

                  JpaDao的構造方法是通過ParameterizedType獲取具體的實體類。

              通過@PersistenceContext 獲取EntityManager

                  entityClassEntityManagerProtected類型,子類可以直接訪問。

          特殊的DAO實現

          最后,我們創建特殊的DAO,它擴張了基本的DAO接口實現了OrderDAO接口

          public class JpaOrderDao extends JpaDao<Integer, Order> implements OrderDao {
                  public List<Order> findOrdersSubmittedSince(Date date) {
                         Query q = entityManager.createQuery(
                                 "SELECT e FROM " + entityClass.getName() + " e WHERE date >= :date_since");
                         q.setParameter("date_since", date);
                         return (List<Order>) q.getResultList();

          DAO的使用

          EJB3中,

          @EJB(name="orderDao")
          private OrderDao orderDao;
           
          在Spring中,我們使用XML bean 文件,或者通過autowiring 如下:
           
          @Autowired
          public OrderDao orderDao;
           
          總之。當我們獲取到了DAO的引用后,我們可以如下使用:
           
          Order o = new Order();
          o.setCustomerName("Peter Johnson");
          o.setDate(new Date());
          orderDao.persist(o);
           
          當然,我們可以再OrderDao接口中加入其它的查詢:
          List<Order> orders = orderDao.findOrdersSubmittedSince(date);
          for (Order each : orders) {
                  System.out.println("order id = " + each.getId());
          }
           
           
           總之,使用了類型安全的DAO Pattern有如下優勢:
              1.    從Client的角度講,不會直接依賴于JPA的API
              2.    通過泛型實現類型安全,避免Cast異常。
              3.    集中處理所有跟JPA相關的代碼。
              4.    可以在集中點上加入事務,log 性能測試等邏輯。
              5.    通過一個類可以測試數據庫訪問代碼。
            希望這些可以說服你使用DAO Pattern . 接下來我們將討論Bidirectional assocations 雙向關聯模式。
           
           
           

          posted on 2009-07-26 12:32 advincenting 閱讀(3516) 評論(1)  編輯  收藏 所屬分類: java EE

          評論

          # re: JPA 設計模式系列一 DAO Pattern in JPA 2009-07-26 18:11 ahx

          很不喜歡 1280x 的布局,或者像首頁一樣自適應,或者使用1024x768 布局;
          因為,看一行字還需要轉腦袋,太累。 1024的最多需要轉一下眼睛。
            回復  更多評論   

          公告

          Locations of visitors to this pageBlogJava
        1. 首頁
        2. 新隨筆
        3. 聯系
        4. 聚合
        5. 管理
        6. <2009年7月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          統計

          常用鏈接

          留言簿(13)

          隨筆分類(71)

          隨筆檔案(179)

          文章檔案(13)

          新聞分類

          IT人的英語學習網站

          JAVA站點

          優秀個人博客鏈接

          官網學習站點

          生活工作站點

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 内丘县| 兴国县| 蓝山县| 新巴尔虎右旗| 瑞丽市| 珲春市| 内乡县| 乌兰浩特市| 垫江县| 柘荣县| 房产| 融水| 屯门区| 长宁区| 漯河市| 天等县| 商丘市| 平阴县| 泉州市| 库尔勒市| 同江市| 峡江县| 禹城市| 涟水县| 石楼县| 平遥县| 麟游县| 会同县| 无极县| 万宁市| 高雄市| 夏邑县| 襄汾县| 南宁市| 石林| 罗江县| 务川| 浙江省| 襄汾县| 陵川县| 韶山市|