2014-01-15 29 views
6

當在CMT(EJB3)中使用以下編程事務和會話語句並且Hibernate Core設置爲使用CMT時會發生什麼?
假定所需要的電流CMT事務,並使用默認@TransactionAttribute(REQUIRED)Hibernate - 使用編程事務語法的CMT EJB

  1. 請問Hibernate事務加入當前CMT上beginTransaction()開始了嗎?
  2. commit()嘗試立即提交hibernate事務或等到當前的CMT提交?
  3. 在CMT中關閉會話時會發生什麼?

B.如果當前會話使用getCurrentSession()綁定到CMT,行爲是否會取決於?

// A: openSession() 
// B: getCurrentSession(); 
Session session = sessionFactory.openSession(); 
Transaction tx = null; 
try 
{ 
    tx = session.beginTransaction(); 

    // do some work 

    tx.commit(); 
} 
catch (final RuntimeException e) 
{ 
    try 
    { 
     tx.rollback(); 
    } 
    catch (final RuntimeException e) 
    { 
     // log error 
    } 
    throw e; 
} 
finally 
{ 
    session.close(); 
} 

在我的應用程序目前我使用一個單一的數據庫,它能正常工作使用編程JDBC事務與Hibernate。現在,該應用程序還使用JMS-Queue進行郵件消息傳遞,並希望將其合併到全局CMT事務中。

編輯:

在我不是在所有的應用程序中使用的EntityManager,也想保留的代碼移植到非託管環境的時刻。

Hibernate配置hibernate.cfg.xml啓用CMT:

休眠4.2.6和Glassfish 3.1.2

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> 
<property name="hibernate.connection.autocommit">false</property> 
<property name="hibernate.connection.datasource">jdbc/datasource</property> 
<property name="hibernate.current_session_context_class">jta</property> 
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</property> 
<property name="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.SunOneJtaPlatform</property> 

SessionFactory的檢索

會話工廠是一個單EJB內建立。 剝離不必要的東西。

@Startup 
@Singleton 
public class SessionManager 
{ 
    private SessionFactory sessionFactory; 

    public SessionManager() 
    { 
     final Configuration configuration = new Configuration().configure(); 
     this.sessionFactory = configuration.buildSessionFactory(); 
    } 
} 

回答

1

至於陸先生指出,這是不是它在CMT環境代碼的方式。無論如何,部分根據 http://docs.jboss.org/hibernate/annotations/3.5/api/org/hibernate/Session.html#beginTransaction%28%29它說

如果需要新的基礎交易,開始交易在這裏是安全的。否則繼續在現有基礎交易背景下的新工作

tx.rollback()也是安全的。它沒有在文檔中說明,但CMTTransaction實際上執行getTransaction().setRollbackOnly(),即它只是標記回滾的TX。提交實際上不提交TX,但可以刷新會話。如果涉及多個資源,真正的提交將違反事務語義。

+0

感謝您的回答。對我來說,'session.beginTransaction()'的描述並不清楚哪個事務是指(Hibernate或JTA)。 – djmj

+0

http://docs.jboss.org/hibernate/annotations/3.5/api/org/hibernate/Transaction.html 似乎它既可以是純粹的jdbc之一,只要取決於TransactionFactory – Gab

+0

一般來說是的,但不是在問題的設置中(除非你錯誤地配置了你的TransactionFactory)。 – Drunix

1

隨着CMT(容器管理事務)不聲明任何類似TX = session.beginTransaction();你讓容器爲你做好工作。您只能指定容器何時以及是否支持事務。查看oracle文檔Java EE 5 Tutorial

假設你有一個EJB,它的默認事務範圍是Required。所以hibernate實際上會被綁定到這個事務範圍。

下面的例子與沒有交易它調用另一個與第一EJB一個CMT:

@TransactionAttribute(NOT_SUPPORTED) 
@Stateful 
public class TransactionBean implements TransactionInterface{ 

    @EJB BusinessBean businessBean; 

    public method1(){ 
     businessBean.doSomething(); 
    } 
} 

@TransactionAttribute(REQUIRED) 
@Stateful 
public class BusinessBean implements BusinessInterface{ 

    @PersistenceContext(unitName = "some-persistence-unit") 
    private EntityManager entityManager; 

    public void doSomething(){ 
     Someclass entity = entityManager.finde(Someclass.class, 1) // Find entity with id 1 
     entity.setData("somedata"); 
    } 
} 

當梅索德doSomething的()完成後,該容器將刷新和提交更新到databese由於外ejb沒有正在運行的事務。這隻適用於容器也提供數據源的情況

+0

'你不喜歡聲明TX = session.beginTransaction什麼()'這就是爲什麼我問,如果你搭配CMT管理Hibernate事務與程序性事務處理,以保持代碼的可移植性會發生什麼。 – djmj

0

會話(在JPA persistence context中,與EntityManager實例關聯)是數據庫模式子集狀態的「內存中」快照。 根據您的配置,會話的範圍會有所不同。在標準的Web應用程序中,每個請求將有一個會話。

你可以有在同一時間不同的狀態會話的許多情況下,會話隔離每個人(操作上的會話執行不是一個又一個可見)

事務是(工作單位理論一個會議也)。它綁定到底層的RDBMS事務系統,並綁定到它打開的會話。

在「容器管理實體管理器」上下文中(您正在調用CMT),容器將負責將您的會話綁定到定義的範圍,並根據遇到的方法調用@Transactional批註傳播事務。

實際上發生了什麼: 您的容器在某處維護一個會話實例,並且能夠使用@PersistenceContext註釋將其提供給您的ejb實例。 您正在使用sessionFactory.openSession()手動構建新會話實例,並在其上打開交易並執行操作。直到您提交事務,手動刷新或關閉自定義會話並手動觸發容器刷新,受管會話實例才能看到任何修改。

getCurrentSession()方法是一種hibernate特定機制,充當Java SE上下文(無容器)中的容器會話作用域管理機制。我想(但我不知道休眠的JPA實現)它不會返回容器管理會話,但我可能在這一點上是錯誤的。 (編輯我)

這裏妥善解決將是檢索使用@PersistenceContext當前容器管理的會話實例,並使用@Transactional註釋來管理事務傳播。

https://community.jboss.org/wiki/SessionsAndTransactions下面

FYI

見陸先生anwser見Container-Managed Transactions

編輯(根據問題版)

Difference between a "jta-datasource" and a " resource-local " datasource?

事實上,看來我是有效的錯誤和t你不需要使用容器中的持久化上下文注入,但是你必須使用JTA事務。

從EJB 3.0規範,部分13.3.4企業Bean使用容器管理的事務劃分:

The enterprise bean’s business methods [...] must not attempt to obtain or use the javax.transaction.UserTransaction interface. 

這意味着你可以使用

sessionFactory.getCurrentSession() 

,但你不能使用TX =會話。的BeginTransaction(),而是

@TransactionAttribute(TransactionAttributeType.REQUIRED) 

見事務劃分在JBoss文檔上面

+0

從您鏈接的jboss文檔中我看不到我不能使用它。或者我錯過了它。它只是指出了一個建議(如Hibernate官方文檔相同)'而是編碼開始,提交和您的交易回滾到應用程序的的確是沒有在JBoss的文檔,清楚地禁止這個,你可以使用一個聲明approach.' – djmj

+0

方法,但是建議的方法是使用聲明式方法。如果'beginTransaction()'返回的有效實現類型是'CMTTransaction',那麼你的方法可能會起作用。 – Gab

+0

我'可能過於依賴於JPA的方式,我不知道是休眠如此靈活,你的問題是一個很好的一個,並明確應該得到更多的利益 – Gab

0

EJB/CMT節中,我學到新的東西從你的問題,因爲我不知道Hibernate可以這種方式進行配置(雖然很明顯它支持JTA)。根據文檔反正看來你不會被迫將其配置爲使用JTA,因爲它是描述here

如果你的持久層中的應用服務器上運行(例如, 背後會話EJB beans),每個數據源連接通過 獲得,Hibernate將自動成爲全局JTA事務的一部分。 您還可以安裝一個獨立的JTA實現,使用它 沒有EJB。 Hibernate爲JTA集成提供了兩種策略。

另請參閱文檔中的示例,因爲您不需要在CMT上下文中打開任何事務。但是,如果您想控制事務分界,請檢查這些BMT示例。

+1

謝謝您的回答。我現在測試並調試它:'beginTransaction()'檢索到的hibernate事務類型爲'CMTTransaction',狀態設置爲'JOINED'。並且它在方法返回時提交,當容器事務也將提交。我在方法返回之前添加了一個斷點來檢查它。觀察到使用容器-jta綁定會話通過'getCurrentSession()'相同的行爲(省略'session.close()',因爲容器關閉它)。現在我很困惑。 – djmj

+0

休眠'CMTTransaction'已加入'()'方法與基礎交易的加盟,但在我的設置則默認情況下加入。 – djmj

+0

你介意告訴我們你如何獲得sesionFactory和你的persistence.xml/hibernate配置嗎? –