簡體   English   中英

將spring JDBC事務與hibernate事務隔離開來

[英]Isolating a spring JDBC transaction from a hibernate transaction

在Spring中,HibernateTransactionManager使用它初始化的SessionFactory在創建新事務時將Session“綁定”到當前線程上下文。 然后,當使用HibernateTemplate時,它會找到綁定的Session並使用它。

但是我今天發現HTM還將其事務綁定到底層DataSource以及SessionFactory(如果可能的話)。 這允許代碼在事務范圍內使用JdbcTemplate,並且如果JdbcTemplate使用的DataSource與SessionFactory使用的相同,則Jdbc操作將參與事務(使用相同的底層連接)。

今天,當我在我的hibernate id分配器中創建了一些代碼來創建一個DataSourceTransactionManager和JdbcTemplate以從高級表中分配id時,這一點非常糟糕。 我打算這是一個獨立的事務,它將獲取下一個高位數,然后將更改提交給id表。 然而,由於上述行為,它實際上參與了我的“外部”hibernate事務,更糟糕的是提前提交它。 我只想說不好。

我嘗試使用事務傳播設置(使用REQUIRES_NEW),但這沒有幫助。

有沒有人知道在hibernate事務中使用JdbcTemplate的最佳方法,而不是讓它們共享一個事務,即使它們共享相同的DataSource?

編輯:

我有一個SessionFactory(S),它由Spring LocalSessionFactoryBean使用DataSource(D)創建。 使用該SessionFactory(S)創建HibernateTransactionManager。

一些業務邏輯代碼看起來像這樣..

hibernateTransactionOperations.execute( new TransactionCallbackWithoutResult()
{
    @Override
    protected void doInTransactionWithoutResult( TransactionStatus status )
    {
        // some transactional code here using a HibernateTemplate

        // will include calls to id allocation when doing hibernateTemplate.save(obj)
    }
} );

我的id分配執行此操作(釋義),下面的DataSource與SessionFactory(S)中使用的相同(D)。

PlatformTransactionManager txManager = new DataSourceTransactionManager( dataSource );
TransactionOperations transactionOperations = new TransactionTemplate( txManager );

return transactionOperations.execute( new TransactionCallback<Long>()
{
    public Long doInTransaction( TransactionStatus status )
    {
        return allocateBatchTxn( idKey, batchSize );
    }
} );

當transactionOperations在上面執行完成時,它將提交底層事務,它似乎與'外部'hibernate事務相同。 我通過檢查數據庫中的鎖/事務來確認這一點。

我用REQUIRES_NEW嘗試了它 - 它按預期工作(在HSQLDB上),也許它依賴於DB:

// txManager is a HibernateTransactionManager obtained from the application context
TransactionOperations transactionOperations = new TransactionTemplate( txManager );
transactionOperations.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);

return transactionOperations.execute(new TransactionCallback<Long>() {
    public Long doInTransaction( TransactionStatus status ) {
        return allocateBatchTxn( idKey, batchSize );
    }
}); 

不要在id分配代碼中創建新的DataSourceTransactionManager。 而是使用REQUIRES_NEW和HibernateTransactionManager

allocateBatchTxn() ,獲取JDBC連接的最安全方法是通過Spring的DataSourceUtils.getConnection()方法。

回答我自己的問題。

我的問題的根本原因是HibernateTransactionManager中的一些事情。

  • 設置'autodetectDataSource',默認為true
  • 在具有上述true的afterPropertiesSet()中,它會自動檢測SessionFactory中的DataSource
  • 在doBegin()中,如果DataSource不為null,它會將新事務綁定到SessionFactory和DataSource

這導致了我的問題,因為我還有一個新的DataSourceTransactionManager,它仍然使用相同的底層存儲(TransactionSynchronizationManager)來管理事務,因為兩者都使用DataSource,這會導致txn管理器之間的事務泄漏。 我可能會爭辯說,txn管理器應該在事務資源的密鑰中包含自己的“密鑰/ id”,因此它們是獨立的,但似乎並沒有這樣做。

上面的回應是明智的。 使用hibernate txn管理器而不是創建新的DataSourceTransactionManager然后使用REQURES_NEW可以解決問題。 但是在我的情況下會在HTM - > SessionFactory - > IdAllocator - > HTM之間引入循環依賴。

我提出了一個有效但不是最優雅的解決方案。

當構造函數id分配器時,它在構造函數中傳遞一個DataSource。 我只是將DataSource包裝在一個100%傳遞的委托包裝器中。 這會更改DataSource引用,因此txn邏輯不會認為正在進行中的事務並且按我的意願工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM