Hibernate-jdon框架事務邊界及session的一些討論

轉自jdon論壇 oojdon提問:

//數據庫請求到來,從當前ThreadLocal取session並開始事務
public Session getSession() throws HibernateException {  
Session sess = (Session)SessionFactoryHolder.getSession();
if (sess == null) {
sess = getFactory().openSession();

Transaction tr = sess.beginTransaction();

SessionFactoryHolder.setSession(sess);

SessionFactoryHolder.setTransaction(tr);
}
return sess;
}


//CloseSessionInView,提交事務
public void closeSession() throws HibernateException { 

Transaction tr = (Transaction) SessionFactoryHolder.getTransactio();

try {
if (tr != null; !tr.wasCommitted(); !tr.wasRolledBack()) {
tr.commit();
}
} catch (Exception e) {
}finally{
SessionFactoryHolder.setTransaction(null);

SessionFactoryHolder.getSession().close();

SessionFactoryHolder.setSession(null);
}
}


1,沒有使用Hibernate的JiveJdon,持久層使用JdbcTemp,沒有事務,默認自動提交

public void createTopicMessage(EventModel em) throws Exception { 

ForumMessage forumMessage = (ForumMessage)em.getModelIF();

Forum forum = forumBuilder.getForum(forumMessage.getForu().getForumId());

forumMessage.setForum(forum);

ForumThread forumThread = super.createThread(forumMessage);

forumMessage.setForumThread(forumThread);

messageDaoFacade.getMessageDao().createMessage(forumMessage);

}


2,沒有使用Hibernate的JiveJdon,持久層使用JdbcTemp,使用JTA事務接口

public void createTopicMessage(EventModel em) throws Exception { 
ForumMessage forumMessage = (ForumMessage)em.getModelIF();

Forum forum = forumBuilder.getForum(forumMessage.getForum().getForumId());

forumMessage.setForum(forum);

TransactionManager tx = jtaTransactionUtil.getTransactionManager();
try {
tx.begin();

ForumThread forumThread = super.createThread(forumMessage);

forumMessage.setForumThread(forumThread);

messageDaoFacade.getMessageDao().createMessage(forumMessage);

tx.commit();
}catch (Exception e) {
logger.error(e);
jtaTransactionUtil.rollback(tx);
throw new Exception(e);
}
}


3,使用了Hibernate的JiveJdon,使用jdon框架整合Hibernate的事務處理----事務邊界是數據庫請求—>頁面渲染結束

public void createTopicMessage(EventModel em) throws Exception { 

ForumMessage forumMessage = (ForumMessage)em.getModelIF();

Forum forum = forumBuilder.getForum(forumMessage.getForum().getForumId());

forumMessage.setForum(forum);

ForumThread forumThread = super.createThread(forumMessage);

forumMessage.setForumThread(forumThread);

messageDaoFacade.getMessageDao().createMessage(forumMessage);
}


4, 使用了Hibernate的JiveJdon,但手工使用JTA接口

public void createTopicMessage(EventModel em) throws Exception { 
ForumMessage forumMessage = (ForumMessage)em.getModelIF();

Forum forum = forumBuilder.getForum(forumMessage.getForum().getForumId());

forumMessage.setForum(forum);

TransactionManager tx = jtaTransactionUtil.getTransactionManager();
try {
tx.begin();
ForumThread forumThread = super.createThread(forumMessage);

forumMessage.setForumThread(forumThread);

messageDaoFacade.getMessageDao().createMessage (forumMessage);

tx.commit();

} catch (Exception e) {
logger.error(e);
jtaTransactionUtil.rollback(tx);
throw new Exception(e);
}
}


5,jivejdon已經向EJB平滑升級,所以方法是這樣的

@TransactionAttribute(REQUIRES_NEW) 

public void createTopicMessage(EventModel em) throws Exception {

ForumMessage forumMessage = (ForumMessage)em.getModelIF();

Forum forum = forumBuilder.getForum(forumMessage.getForum().getForumId());

forumMessage.setForum(forum);

ForumThread forumThread = super.createThread(forumMessage);

forumMessage.setForumThread(forumThread);

messageDaoFacade.getMessageDao().createMessage(forumMessage);
}


我比較鬱悶的就是這四,五兩種寫法,事務在方法返回後結束,但是Hibernate的sessin呢?是還打開,還是已經被關閉,如果關閉我的懶加載怎麼辦?

banq等回覆:
我也贊成使用第四 五種方式,在這兩個方式下,我前面帖子寫了,不必關閉session的兩種方式處理事務和Session的關係:
1. 手工在事務結束前session.flush()
2. 配置Hibernate的transaction.mamager爲JTA,讓Hibernete能夠自動進行flush,它會偵測當前是否在一個事務,如果事務結束,它就進行flush,將內存中狀態和數據庫數據進行同步。

事務和Session本來特別關係,事務主要是保證數據庫資源操作的一致性,所以,需要flush來特別操作。

不要將事務搞神祕,事務基本只有兩個JTA長事務(包括跨段2PC事務)和JDBC短事務,Hibernate本質就是JDBC+緩存。事務是JavaEE基礎功能,可以下載JavaEE標準看看,和任何框架都不搭架(除非專門提供事務的框架)。

Spring和EJB一樣,只是提供事務的AOP切入方式,也就是說,無需自己手工寫transaction.begin,因爲AOP攔截器做了。Spring本身沒有提供除JTA/JDBC事務以外任何神祕新的功能。

如果瞭解AOP,就知道:transaction.begin不在當前程序寫,只是移到攔截器中寫,寫的地方不一樣了。這就是區別,因爲不需要你在程序自己寫transaction.begin(這叫顯式調用),也就是隱式調用JTA了,從你眼前隱去了。這個區別就是對JTA事務調用方式的不同,而不是JTA事務本身的不同,不要將這兩者混同在一起。

不要把"JPA、Hibernate、JDO和JTA"混同在一起,JTA是JavaEE基礎功能,而JPA、Hibernate、JDO只是持久化框架,和JTA無關。也就是說,JPA、Hibernate、JDO沒有JTA也可以用,JTA沒有JPA、Hibernate、JDO也可以用。

所以,如果你搞不定JTA,就不急於使用它。JTA通常在Service或業務層來使用(transaction.beigin顯式調用或AOP/EJB的隱式調用),可以跨多個JDBC或其他資源,這個可以參考本站事務標籤瞭解一下。

因爲JTA在業務層使用,纔可能和Spring/EJB這樣框架有點關係,這個關係也就是顯式調用或隱式調用的關係,就像兩個男女,本是獨立的,發生關係了,要麼是顯式聲明的,登記結婚大張旗鼓(表現爲需要寫代碼),要麼就是偷情隱式的,悄悄的(表現爲不需要寫代碼了)。

事務是JavaEE中最複雜的知識,它和原子性 多線程 鎖等有關(所以纔有取款機吐錢,記錄數據沒變化等不一致性,這些都充分說明國人對事務安全非常薄弱),說大了也和並行計算有關(在多個CPU同時執行你的程序情況下,如何保證你業務真正原子性和唯一性,又不能喪失多線程多核的優勢。)。這個世界上最缺的就是編寫併發計算的人,這是有道理的。

另外,要注意:框架和JavaEE組件要有區分。框架實際就是把這些組件扒拉扒拉在一起,方便或約束你使用,從設計上讓你的程序更所謂優雅,當然也有弄巧成拙,搞複雜了,Spring至少是這樣,一些人以爲複雜就是優雅實際被誤導(最可悲就是不自知),所以Spring沒熱多長時間,Ruby on Rails以其簡潔性成爲熱點,這是有原因的,現在Scala又開始熱起來,因爲大家發現RoR慢啊,如果能夠使用多核的DSL多好啊,設計又優雅性能又優雅,雙優雅,這纔是真優雅。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章