2008年7月1日 星期二

Hibernate Session 的 get 與 load

Hibernate Session 為了節省一次 Database Roundtrip,所以:
  • load 只是產生一個 Proxy,或是直接取用目前 Session 中已有的 Cache,不會真的連到 Database
  • get 才會真的連到資料庫,取得一個 Fully Initialized POJO
以前只注意到 get 找不到資料的時候會回傳 null,可是 load 不會。不管 Database 有沒有那筆紀錄,load 的傳回值一定不是 null。詳細探究原因,才知道 load 根本不會殺到 Database,也就沒有機會給 null。

org.hibernate.Session 的 Javadoc 說法是:
  • load:Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists. You should not use this method to determine if an instance exists (use get() instead). Use this only to retrieve an instance that you assume exists, where non-existence would be an actual error.
  • get:Return the persistent instance of the given named entity with the given identifier, or null if there is no such persistent instance. (If the instance, or a proxy for the instance, is already associated with the session, return that instance or proxy.)
這邊看不出為什麼 get 不會拿到 Proxy,但是從 org.hibernate.impl.SessionImpl 的程式碼可以看到:
public Object load(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
return load( entityClass.getName(), id, lockMode );
}

public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
fireLoad( event, LoadEventListener.LOAD );
return event.getResult();
}

public Object get(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
return get( entityClass.getName(), id, lockMode );
}

public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
fireLoad(event, LoadEventListener.GET);
return event.getResult();
}

LoadEventListener 有 LOAD 與 GET 兩種情形。

org.hibernate.event.LoadEventListener 的程式碼中可以看出:
public static final LoadType GET = new LoadType("GET")
.setAllowNulls(true)
.setAllowProxyCreation(false)
.setCheckDeleted(true)
.setNakedEntityReturned(false);

public static final LoadType LOAD = new LoadType("LOAD")
.setAllowNulls(false)
.setAllowProxyCreation(true)
.setCheckDeleted(true)
.setNakedEntityReturned(false);

其中,GET 的時候,setAllowProxyCreation 的參數是 false,應該就表示 GET 的時候不允許產生 Proxy 物件。setAllowNulls 的參數是 true,這應該就是為什麼找不到資料的時候可以回傳 null 的原因吧!

1 則留言:

涼麵 提到...

session.get() 和 session.load()方法的異同:
session.get() method and session.load() methods 都可以根據實體類和所給的ID讀取數據庫中的信息,並返回與之對應的實體對象。
二者的區別:
1.session.get()如果找不到符合條件的記錄,則返回NULL,session.load()如果找不到符合條件的記錄,返回ObjectNotFoundException.
2.session.load()方法可返回代理類實例,而session.get()方法永遠返回實例類.
3.session.load() method 可以充分利用內部緩存和二級緩存,而session.get() method 只在內部緩存中進行查找,如果沒有找到,則跳過二級緩存,直接調用SQL進行數據讀取.