Hibernate與JDO肩並肩

在theServerSide.com上有一些人聲稱JDO的開發人員已經把JDO帶向錯誤的道路,並且指出Hibernate相對更優秀。然而,根據我的經驗Hibernate和JDO都是O/R Mapping的優秀技術。

它們有許多共同的特徵,包括:

  • 支持Plain Old Java Object (POJO) 的幾近透明的持久層
  • 基於XML的object/relational映射
  • 兩者都有一個"EntityManager" API - Hibernate Session 和 JDO PersistenceManager
  • 都可以在或不在Container中運行應用程序
  • 事務級和應用級的cache
  • 豐富的查詢語言 (query language)
  • 能夠積極和消極兩種方式裝載有關聯的對象
  • 有效率地處理大數據集合

因此,JDO 和 Hibernate 兩種版本的同一應用程序經常很相似。

關於如何裝載對象和執行查詢,我們來看看下面的例子。這裏有兩個版本的RestaurantRepository類,一個是JDO的,另一個是Hibernate的。 RestaurantRepository類定義了尋找飯店的方法:

  • findRestaurant() - 找單一飯店 (類似於 findByPrimaryKey()).
  • findAvailableRestaurants() - 執行查詢,找到在特定時間特定區域營業的飯店

列表 1 顯示了JDO版的 RestaurantRepository 類, 列表 2 顯示了Hibernate 的版本。

列表 1 - JDO 版

public class JDORestaurantRepositoryImpl
    implements RestaurantRepositoryImpl {

  public Restaurant findRestaurant(String restaurantId) {
   PersistenceManager pm = PMRegistry.getPM();
   return (Restaurant) pm.getObjectById(
    pm.newObjectIdInstance(
     JDORestaurant.class,
     restaurantId),
    true);
  }


    private static final String QUERY_STRING =
        "serviceArea.contains(zipCode) && timeRanges.contains(tr) && "
            + "(tr.dayOfWeek == day && "
            + "(tr.openHour < hour || (tr.openHour == hour && tr.openMinute <= minute)) && "
            + "(tr.closeHour > hour || (tr.closeHour == hour && tr.closeMinute > minute)))";

    public Collection findRestaurants(
        Address deliveryAddress,
        Date deliveryTime) {
        Calendar c = Calendar.getInstance();
        c.setTime(deliveryTime);
        int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);

        PersistenceManager pm = PMRegistry.getPM();
        Query query = pm.newQuery(JDORestaurant.class, QUERY_STRING);
        query.declareVariables("JDOTimeRange tr");
        query.declareParameters(
            "String zipCode, int day, int hour, int minute");
        Collection result =
            (Collection) query.executeWithArray(
                new Object[] {
                    deliveryAddress.getZip(),
                    new Integer(dayOfWeek),
                    new Integer(hour),
                    new Integer(minute)});
        return result;
    }
}

 

列表 2 - Hibernate 版

public class HibernateRestaurantRepositoryImpl
    implements RestaurantRepositoryImpl {

    public Restaurant findRestaurant(String restaurantId) {
        try {
            Session session = HibernateSessionRegistry.getSession();
            Restaurant restaurant =
                (Restaurant) session.load(
                    HibernateRestaurant.class,
                    new Long(restaurantId));
            return restaurant;
        } catch (HibernateException e) {
            throw new ApplicationRuntimeException(e);
        }
    }

    public Collection findRestaurants(
        Address deliveryAddress,
        Date deliveryTime) {
        try {
            Query query =
                makeFindRestaurantsQuery(
                    deliveryAddress,
                    deliveryTime);
            return query.list();
        } catch (HibernateException e) {
            throw new ApplicationRuntimeException(e);
        }
    }

    private Query makeFindRestaurantsQuery(
        Address deliveryAddress,
        Date deliveryTime)
        throws HibernateException {
        Calendar c = Calendar.getInstance();
        c.setTime(deliveryTime);
        int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        Session session = HibernateSessionRegistry.getSession();
        Query query =
            session.getNamedQuery("findAvailableRestaurants");
        query.setString("zipCode", deliveryAddress.getZip());
        query.setInteger("dayOfWeek", dayOfWeek);
        query.setInteger("hour", hour);
        query.setInteger("minute", minute);
        query.setCacheable(true);
        return query;
    }
}

每個 repository 由兩個方法組成。這兩個方法調用相應的 persistence framework API:

  • findRestaurant() - JDO 版調用 PersistenceManager.getObjectById() 而 Hibernate版調用 Session.load()
  • findAvailableRestaurants() - 兩個版本都使用Query interface來執行有名參數的查詢. 有個不同的地方,Hibernate 版用 named query, named query會在一個映射文件中定義,而 JDO 版用鑲嵌在類裏的 query 

兩個類通過 ThreadLocal-based registry 得到 Hibernate Session 和 JDO PersistenceManager。如你所見,除了方法和類的名字不同,其它code都非常相似。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章