javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction"); Session s1 = sf.openSession(); ... s1.flush(); s1.close(); ... Session s2 = sf.openSession(); ... s2.flush(); s2.close(); tx.commit(); |
這是標準的使用JTA的代碼片斷,Transaction是跨Session的,它的生命週期比Session要長。如果你在EJB中使用Hibernate,那麼是最簡單不過的了,你什麼Transaction代碼統統都不要寫了,直接在EJB的部署描述符上配置某某方法是否使用事務就可以了。
現在我們來分析一下JTATransaction的源代碼, net.sf.hibernate.transaction.JTATransaction:
public void begin(InitialContext context, ... ... ut = (UserTransaction) context.lookup(utName); ... |
看清楚了嗎? 和我上面寫的代碼 tx = new Initial Context?().lookup("javax.transaction.UserTransaction"); 是不是完全一樣?
public void commit() ... ... if (newTransaction) ut.commit(); ... |
JTATransaction的控制稍微複雜,不過仍然可以很清楚的看出來Hibernate是如何封裝JTA的Transaction代碼的。
但是你現在是否看到了什麼問題? 仔細想一下,Hibernate Transaction是從Session中獲得的,tx = session.beginTransaction(),最後要先提交tx,然後再session.close,這完全符合JDBC的Transaction的操作順序,但是這個順序是和JTA的Transactioin操作順序徹底矛盾的!!! JTA是先啓動Transaction,然後啓動Session,關閉Session,最後提交Transaction,因此當你使用JTA的Transaction的時候,那麼就千萬不要使用Hibernate的Transaction,而是應該像我上面的JTA的代碼片斷那樣使用纔行。
總結:
1、在JDBC上使用Hibernate 必須寫上Hibernate Transaction代碼,否則數據庫沒有反應。此時Hibernate的Transaction就是Connection.commit而已
2、在JTA上使用Hibernate 寫JTA的Transaction代碼,不要寫Hibernate的Transaction代碼,否則程序會報錯
3、在EJB上使用Hibernate 什麼Transactioin代碼都不要寫,在EJB的部署描述符裏面配置
|---CMT(Container Managed Transaction)
|
|---BMT(Bean Managed Transaction)
|
|----JDBC Transaction
|
|----JTA Transaction