Hibernate 是JDBC 的輕量級封裝本身並不具備事務管理能力在事務管理層Hibernate將其委托給底層的JDBC或者JTA以實現事務管理和調度功能
Hibernate的默認事務處理機制基於JDBC Transaction我們也可以通過配置文件設定采用JTA作為事務管理實現
Java代碼
<hibernateconfiguration>
<sessionfactory>
……
<property name=hibernatetransactionfactory_class>
netsfhibernatetransactionJTATransactionFactory
<!netsfhibernatetransactionJDBCTransactionFactory>
</property>
……
</sessionfactory>
</hibernateconfiguration>
<hibernateconfiguration>
<sessionfactory>
……
<property name=hibernatetransactionfactory_class>
netsfhibernatetransactionJTATransactionFactory
<!netsfhibernatetransactionJDBCTransactionFactory>
</property>
……
</sessionfactory>
</hibernateconfiguration>
基於JDBC的事務管理將事務管理委托給JDBC 進行處理無疑是最簡單的實現方式
Hibernate 對於JDBC事務的封裝也極為簡單
我們來看下面這段代碼
Java代碼
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
……
mit();
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
……
mit();
從JDBC層面而言
上面的代碼實際上對應著
Java代碼
Connection dbconn = getConnection();
dbconnsetAutoCommit(false);
……
mit();
Connection dbconn = getConnection();
dbconnsetAutoCommit(false);
……
mit();
就是這麼簡單
Hibernate並沒有做更多的事情(實際上也沒法做更多的事情)
只是將這樣的JDBC代碼進行了封裝而已
這裡要注意的是
在sessionFactory
openSession()中
hibernate會初始化數據庫連接
與此同時
將其AutoCommit 設為關閉狀態(false)
而其後
在Session
beginTransaction 方法中
Hibernate 會再次確認Connection 的AutoCommit 屬性被設為關閉狀態( 為了防止用戶代碼對session 的Connection
AutoCommit屬性進行修改)
這也就是說
我們一開始從SessionFactory獲得的session
其自動提交屬性就已經被關閉(AutoCommit=false)
下面的代碼將不會對數據庫產生任何效果
Java代碼
session = sessionFactoryopenSession();
sessionsave(user);
sessionclose();
session = sessionFactoryopenSession();
sessionsave(user);
sessionclose();
這實際上相當於 JDBC Connection的AutoCommit屬性被設為false
執行了若干JDBC操作之後
沒有調用commit操作即將Connection關閉
如果要使代碼真正作用到數據庫
我們必須顯式的調用Transaction指令
Java代碼
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
sessionsave(user);
mit();
sessionclose();
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
sessionsave(user);
mit();
sessionclose();
基於JTA的事務管理 JTA 提供了跨Session 的事務管理能力
這一點是與JDBC Transaction 最大的差異
JDBC事務由Connnection管理
也就是說
事務管理實際上是在JDBC Connection中實現
事務周期限於Connection的生命周期之類
同樣
對於基於JDBC Transaction的Hibernate 事務管理機制而言
事務管理在Session 所依托的JDBC Connection中實現
事務周期限於Session的生命周期
JTA 事務管理則由 JTA 容器實現
JTA 容器對當前加入事務的眾多Connection 進
行調度
實現其事務性要求
JTA的事務周期可橫跨多個JDBC Connection生命周期
同樣對於基於JTA事務的Hibernate而言
JTA事務橫跨可橫跨多個Session
JTA 事務是由JTA Container 維護
而參與事務的Connection無需對事務管理進行干涉
這也就是說
如果采用JTA Transaction
我們不應該再調用HibernateTransaction功能
上面基於JDBC Transaction的正確代碼
這裡就會產生問題
Java代碼
public class ClassA{
public void saveUser(User user){
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
sessionsave(user);
mit();
sessionclose();
}
}
public class ClassB{
public void saveOrder(Order order){
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
sessionsave(order);
mit();
sessionclose();
}
}
public class ClassC{
public void save(){
……
UserTransaction tx = new InitialContext()lookup(……);
ClassAsave(user);
ClassBsave(order);
mit();
……
}
}
public class ClassA{
public void saveUser(User user){
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
sessionsave(user);
mit();
sessionclose();
}
}
public class ClassB{
public void saveOrder(Order order){
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
sessionsave(order);
mit();
sessionclose();
}
}
public class ClassC{
public void save(){
……
UserTransaction tx = new InitialContext()lookup(……);
ClassAsave(user);
ClassBsave(order);
mit();
……
}
}
這裡有兩個類ClassA和ClassB
分別提供了兩個方法
saveUsersaveOrder
用於保存用戶信息和訂單信息
在ClassC中
我們接連調用了ClassA
saveUser方法和ClassB
saveOrder 方法
同時引入了JTA 中的UserTransaction 以實現ClassC
save方法中的事務性
問題出現了
ClassA 和ClassB 中分別都調用了Hibernate 的Transaction 功能
在Hibernate 的JTA 封裝中
Session
beginTransaction 同樣也執行了InitialContext
lookup方法獲取UserTransaction實例
mit方法同樣也調用了mit方法
實際上
這就形成了兩個嵌套式的JTA Transaction
ClassC 申明了一個事務
而在ClassC 事務周期內
ClassA 和ClassB也企圖申明自己的事務
這將導致運行期錯誤
因此
如果決定采用JTA Transaction
應避免再重復調用Hibernate 的
Transaction功能
上面的代碼修改如下
Java代碼
public class ClassA{
public void save(TUser user){
session = sessionFactoryopenSession();
sessionsave(user);
sessionclose();
}
……
}
public class ClassB{
public void save (Order order){
session = sessionFactoryopenSession();
sessionsave(order);
sessionclose();
}
……
}
public class ClassC{
public void save(){
……
UserTransaction tx = new InitialContext()lookup(……);
classAsave(user);
classBsave(order);
mit();
……
}
}
public class ClassA{
public void save(TUser user){
session = sessionFactoryopenSession();
sessionsave(user);
sessionclose();
}
……
}
public class ClassB{
public void save (Order order){
session = sessionFactoryopenSession();
sessionsave(order);
sessionclose();
}
……
}
public class ClassC{
public void save(){
……
UserTransaction tx = new InitialContext()lookup(……);
classAsave(user);
classBsave(order);
mit();
……
}
}
上面代碼中的ClassC
save方法
也可以改成這樣
Java代碼
public class ClassC{
public void save(){
……
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
classAsave(user);
classBsave(order);
mit();
……
}
}
public class ClassC{
public void save(){
……
session = sessionFactoryopenSession();
Transaction tx = sessionbeginTransaction();
classAsave(user);
classBsave(order);
mit();
……
}
}
實際上
這是利用Hibernate來完成啟動和提交UserTransaction的功能
但這樣的做法比原本直接通過InitialContext獲取UserTransaction 的做法消耗了更多的資源
得不償失
在EJB 中使用JTA Transaction 無疑最為簡便
我們只需要將save 方法配置為JTA事務支持即可
無需顯式申明任何事務
下面是一個Session Bean的save方法
它的事務屬性被申明為
Required
EJB容器將自動維護此方法執行過程中的事務
Java代碼
/**
* @ejbinterfacemethod
* viewtype=remote
*
* @ejbtransaction type = Required
**/
public void save(){
//EJB環境中通過部署配置即可實現事務申明而無需顯式調用事務
classAsave(user);
classBsave(log);
}//方法結束時如果沒有異常發生則事務由EJB容器自動提交
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28740.html