2011-01-19 14 views
3

春期にHibernateTransactionManagerは、新しいトランザクションを作成するときにSessionを初期化したSessionFactoryを使用して、現在のスレッドコンテキストにSessionをバインドします。次に、HibernateTemplateが使用されるとき、それはバインドされたSessionを見つけてそれを使用します。休止状態のJDBCトランザクションを休止状態のトランザクションから切り離す

しかし、私は今日、HTMがそのトランザクションを基になるDataSourceとSessionFactory(可能であれば)にバインドしていることを発見しました。これにより、コードがトランザクションスコープ内でJdbcTemplateを使用できるようになり、JdbcTemplateで使用されるDataSourceがSessionFactoryの使用と同じであれば、Jdbc操作は(同じ基本Connectionを使用して)トランザクションに参加します。

今日私は、ハイローテーブルからIDを割り当てるために、DataSourceTransactionManagerとJdbcTemplateを作成していた自分のhibernate idアロケータにいくつかのコードを持っていました。私は、これが次の高い数値を取り出してidテーブルにコミットするスタンドアロントランザクションであることを意図していました。しかし、上記の動作のために、実際には私の「外側の」休止状態のトランザクションに参加していて、それを早期にさらに悪化させていました。良くないとは言えません。

トランザクションプロポーション設定(REQUIRES_NEWを使用)を試してみましたが、これは役に立ちませんでした。

誰でも、同じデータソースを共有していても、休止状態のトランザクション内でJdbcTemplateを使用し、トランザクションを共有する最良の方法を知っていますか?

EDIT:

Iは、データソース(D)を用いLocalSessionFactoryBeanスプリングによって作成されるのSessionFactory(S)を有します。 HibernateTransactionManagerはそのSessionFactory(S)で作成されます。

いくつかのビジネス・ロジック・コードは次のようになり

..

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の割り当ては(言い換え)この処理を行い、以下のデータソースは、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が実行されると、 'outer' hibernateトランザクションと同じように見える基本トランザクションがコミットされます。 DBのロック/トランザクションをチェックすることでこれを確認しました。

+0

'DataSourceTransactionManager' *は、Hibernate txに依存しない新しいtx接続と新しい接続を開始する必要があります。あなたが行ったことを説明するために、いくつかのコード/設定を表示できますか? – skaffman

+0

ログをDEBUGに変更してみてください。 Springは、トランザクションの同期と接続の管理について、多くのデバッグレベルのロギングを行います。非常に冗長ですが、診断に関しては非常に役立ちます。 – skaffman

答えて

2

私自身の質問に答える。

私の問題の根本原因は、HibernateTransactionManagerにいくつかあります。

  • 設定上記真でそれがdoBeginでのSessionFactory
  • (からDataSourceを自動検出afterPropertiesSetにおいて
  • デフォルトはtrue() 'autodetectDataSource')DataSourceが、それは意志nullでない場合新しいトランザクションをSessionFactoryとDataSourceにバインドする

これは、トランザクションを管理するために同じ基本ストレージ(TransactionSynchronizationManager)を使用する新しいDataSourceTransactionManagerも持っているため、私の問題を引き起こしています。 txnマネージャ間でこのようなトランザクションの漏洩を取得するDataSourceを使用します。私は、txnマネージャーがトランザクションリソースのキーに独自の 'key/id'を含める必要があるので、独立しているが、そのようには見えないと主張するかもしれない。

上記の応答は適切です。新しいDataSourceTransactionManagerを作成せずにREQURES_NEWを使用する代わりに、hibernate txn managerを使用すると問題が解決します。しかし、私の場合は、HTM - > SessionFactory - > IdAllocator - > HTMの間に循環依存関係が導入されます。

私は動作するソリューションを考え出しましたが、これまでで最もエレガントなものではありません。

コンストラクタidアロケータはコンストラクタのDataSourceに渡されます。私は単純にそのDataSourceを100%通過する委任ラッパーにラップします。これによりDataSource参照が変更されるので、txnロジックはトランザクションが進行中であるとは思っておらず、必要に応じて動作します。

2

私は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); 
    } 
}); 
2

があなたのID割り当てコードに新しいDataSourceTransactionManagerを作成しないでください。代わりに、REQUIRES_NEWとHibernateTransactionManagerを使用してください。

allocateBatchTxn()では、JDBC接続を取得する最も安全な方法は、SpringのDataSourceUtils.getConnection()メソッドです。

+0

これはうまくいくならば理想的ですが、SessionFactoryがIDアロケータで初期化できないため、Springのセットアップで循環依存を作成します。 –