2008年7月2日 星期三

Spring Framework HibernateTemplate 的 initialize 方法

Spring Framework 提供了 HibernateTemplate,封裝 Hibernate Session 重要的 API,簡化程式的撰寫。

Session 的 load 與 get 有差異,HibernateTemplate 封裝的 load 與 get 當然就有差異,看 HibernateTemplate 的原始程式就很清楚:
public Object load(final Class entityClass, final Serializable id, final LockMode lockMode)
throws DataAccessException {

return executeWithNativeSession(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return session.load(entityClass, id, lockMode);
}
else {
return session.load(entityClass, id);
}
}
});
}

public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)
throws DataAccessException {

return executeWithNativeSession(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return session.get(entityClass, id, lockMode);
}
else {
return session.get(entityClass, id);
}
}
});
}
可是有一件事很有趣,原本使用 Session/Transaction 這樣寫的程式碼:
try
{
tx = session.beginTransaction();
book = (Book) session.load(Book.class, bookID);
Hibernate.initialize(book);
tx.commit();
}
catch (Exception e)
{
if (tx != null) tx.rollback();
e.printStackTrace();
}

不能直接改成底下使用 HibernateTemplate 的寫法:
try
{
book = (Book) hibernateTemplate.load(Book.class, bookID);
hibernateTemplate.initialize(book);
}
catch (Exception e)
{
e.printStackTrace();
}

原因就是 HibernateTemplate 的 Javadoc 所說的:

This class can be considered as direct alternative to working with the raw Hibernate3 Session API (through SessionFactory.getCurrentSession()). The major advantage is its automatic conversion to DataAccessExceptions as well as its capability to fall back to 'auto-commit' style behavior when used outside of transactions. Note that HibernateTemplate will perform its own Session management, not participating in a custom Hibernate CurrentSessionContext unless you explicitly switch "allowCreate" to "false".

可是呢,即使把 allowCreate 設定為 false,還是會有問題:

Caused by: org.hibernate.HibernateException: load is not valid without active transaction

也就是沒有把 load 包在 Transaction 裡頭。

可是如果還要寫出 Transaction 的程式碼,那就麻煩了。

所以呢,就是透過 Spring Framework 提供的 AOP,掛上 Transaction,這時候就不必去設定什麼 allowCreate,直接就可以正常運作了!

沒有留言: