在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类定义了寻找饭店的方法:
列表 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都非常相似。 
|