最近,用各種算是流行的方法寫了些Hibernate的例子(基于測試)。上次打算寫兩篇文章。① Hibernate 常用工具的配置和使用。② Hibernate 比較簡單的,基于單表操作的例子。寫了80%吧。越想越感覺意義不大。現在網上很多這方面的文章。我自己也沒有理由,自私的所謂備份。占用Blogjava的硬盤空間。就成了后來的 “冰 凍 閑 聊”
上個星期五,因為公司停電。所以休息了三天。一年前,這個數字可能會感覺太短。但是現在卻是突然覺得連續三天不上班。不知道該干什么好。
難道是對這種“月光”族的生活上癮拉?… 這樣的話題,等以后想明白了再說吧!~
接著說這個周末吧!因為無聊,翻翻,去年用過的一些散亂的筆記。越看越搞笑,字跡潦草,還好基本上是一些技術痕跡。找不到從前那些“少年不知愁滋味”的感覺。
因為我一直不是很喜歡看書。現在的書,寫得好的不多,但是價錢蠻貴的。所以,有時候就會把一些疑惑的問題寫在一張紙上。然后去網上先收集一些資料,再閱讀總結。
這里,我發現了一條有趣的問題。2004年12月3日 Hibernate使用JDBC和JTA管理事務有什么區別?傻傻的問題。不如今天就聊聊這個話題吧!可能,現在也會有人對這個問題感覺疑惑的。
打開hibernate.cfg.xml看看具體的JDBCTransaction 和 JTATransaction 配置:
1
1)
2
<property name="hibernate.transaction.factory_class">
3
org.hibernate.transaction.JDBCTransactionFactory
4
</property>
5
6
2)
7
<property name="hibernate.transaction.factory_class">
8
org.hibernate.transaction.JTATransactionFactory
9
</property>
10
可能你還會問:“除了這兩種還有其他的選擇嗎?到底選擇那一種好呢?在一個應用中能混合使用嗎?”等等問題
分析和解答:
第一個問題
可以選擇其他的事務管理方式。不過都是JTA的不同實現版本。這個目錄下面有羅列出來hibernate-3.0\src\org\hibernate\transaction。比如:
1
<property name="hibernate.transaction.manager_lookup_class">
2
org.hibernate.transaction.WeblogicTransactionManagerLookup
3
</property>
4
第二個問題
概念事務:事務就是能以整體的原子操作形式完成的一系列操作。
是不是感覺有些饒口?簡單的說,事務 就是一個邏輯工作單元。其中包括一系列的操作。至于事務為什么會產生?有什么基本特性?等等。。這些問題今天不就詳細的羅列了。網絡上有寫得很好的文章。
Hibernate 是JDBC的輕量級封裝。他本身并不具備事物管理的能力。事務的管理和調度將委托給JDBC或者JTA去做。
先說,他默認的事務處理機制[ JDBC Transaction ],這的確是最簡單的處理方式,因為Hibernate只是對JDBC事物做了一層簡單
的封裝。JDBC事務由Connection管理。事務周期局限于Connection的生命周期之內。在Hibernate中這種事務周期也就局限于一個Session之內。做個比較吧!
Connection conn = … ; <--- session = sf.openSession();// 初始化數據庫連接,
和setAutoCommit= false;
conn.setAutoCommit(false); <--- tx = session.beginTransactioin(); 會再次確認setAutoCommit是否是false
調用業務方法 <--- 調用業務方法
conn.commit(); <--- tx.commit(); (對應左邊的兩句) 這里很關鍵,關掉自動commit。自己就必須做commit。否則數據是不會被持久到數據庫
conn.setAutoCommit(true);
conn.close(); <--- session.close();
簡單吧!如果你對JDBC有了解,看到這里可能會壞笑,NND就這么簡單,我也會封裝…有興趣的話可以直接去看看具體的源代碼。
看看第二種[JTA Transaction]有什么神奇的地方吧!
JTA 提供了跨Session的事務管理能力。JTA的事務是要容器支持的,即JTS,用來分布式的要求比較多一些,比如像銀行這種大系統,處理多個事務源的這些的。
JTA事務管理則是由JTA容器實現。事務的生命周期完全由容器來維護。容器中可以有很多Connection。按照執行的順序,因該是串聯的一條JDBC Connection事務鏈。所以JTA的事務周期可以跨多個JDBC Connection的生命周期。在Hibernate中這種事務周期也就可以跨越多個Session。
所以。JTA事務的Connection不能對事務管理進行干涉。意思就是,假如使用了JTA就不應該再重復調用Hibernate的Transaction功能。這里涉及到一種事務模型(嵌套式事務模型)的問題。這里也不詳細的介紹具體的幾種事務模型了。在EJB2.0規范里面也不支持這種事務處理模型。
例如 :
1
class A 有一個方法 savePerson()
2
class B 有一個方法 saveAddress()
3
// Call A.savePerson() and B.saveAddress() Used JTATransaction
4
class C 有一個方法 saveAll()
5
UserTransaction tx = (UserTransaction)(new InitialContext.lookup(“…”))
6
A.savePerson();
7
B.saveAddress();
8
tx.commit();
9
那么下面這段代碼
1
Transaction tx = session.beginTransaction();
2
tx.commit();
3
就不能在class A 和 class B 中出現。
原因:session.beginTransaction()也同樣執行了InitialContext.lookup方法來獲UserTransaction的實例,tx.commit()也同樣調用了UserTransaction.commit().這樣做就會形成嵌套式的事務。在Hibernate里面是不被允許的。會導致運行期錯誤。
談到這里,不難看出,他們都有著自己鮮明的特點和基本的聯系。回到開頭的問題,在實際項目中該選用誰好呢?
這就需要分情況而定了。
1) 如果項目有用到Sessionbean.可能你會疑問?這時候由誰來管理事務呢?
答案:用SessionBean來管理。使用JTA會很方便。因為你完全沒有必要去理會Transaction。直接在SessionBean的部署描述符里面聲明事務就行了。
2) 自己實現一個Service類,來統一調用持久層的方法。這樣也能做到前后臺的松耦合。但是這時候你對session和Transaction的處理就需要小心了。如果系統考慮分布式就使用JTA否則就JDBC足夷。但還是有必要考慮系統的升級,變遷什么的。對session和Transaction的處理,最好不要放在DAO里面做。單獨實現一個模板類來統一做。具體的原因和做法,以后有時間再寫出來。
第三個問題
由于SessionFactory是線程安全的,他的創建過程非常復雜,代價極其昂貴。一個應用中最好只有一個SessionFactory。事務管理類型的選擇是在SessionFactory的屬性里面配置的。這里只能選擇一種事務管理方式。
當然,你可以說還有特殊的情況,假如,這個應用需要連接到兩臺數據庫服務器,就必須為他創建另一個SessionFactory。那么就可以選用另一種事務管理方式。表面上看這種情況是可以的。居于兩種事務的性能考慮。混和用的意義不是很大。假設這樣用+面對考慮不周全的DAO,也違背了設計原則,想想,這樣的話,因為數據庫的變動,還得回去修改DAO的代碼嗎?(可能會產生嵌套問題)
所以關于這個問題的結論就是:
在一個SessionFactory中只能選用一種事務管理
面對多個SessionFactory的時候,可以混合用,但是不推薦
2005-11-28 CTU OFFICE GOINGMM