web-dev-qa-db-ja.com

2つのトランザクションマネージャーを使用した@EnableTransactionManagementアノテーション

Xmlファイルの代わりに@Configuration注釈をspringの構成に使用しています。異なるセッションファクトリと異なるトランザクションマネージャーで2つのデータソースを構成しています。ここで@EnableTransactionManagementアノテーションの問題に悩まされています。私はその文書を読んで、

@EnableTransactionManagementはより柔軟です。コンテナ内のPlatformTransactionManager Beanのタイプ別ルックアップにフォールバックします。したがって、名前は「txManager」、「transactionManager」、または「tm」になります。単に問題ではありません。

これは、メソッドに付ける名前に関係なく、トランザクションマネージャーが2つある間は常にPlatformTransactionManagerオブジェクトを返すメソッドを検索します。問題は、このクラスをテストするとエラーが発生することです。

org.springframework.beans.factory.NoSuchBeanDefinitionException:タイプ[org.springframework.transaction.PlatformTransactionManager]の一意のBeanは定義されていません:予期される単一のBeanが見つかりました2

2つの異なる構成クラスを作成しようとしましたが、無駄でした。 xml構成では、そうではありませんでした。 2つの<tx:annotation-driven transaction-manager="" />タグで両方のトランザクションマネージャーを登録しましたが、正常に機能しました。ただし、ここではアノテーションを使用して同じことを行うことはできません。

Spring注釈付き構成クラスで2つの異なるトランザクションマネージャーで2つのデータソースを構成する場合はどうすればよいですか?

25
Mital Pritmani

構成クラスで、@EnableTransactionManagement注釈を使用します。

このクラスでトランザクションマネージャを次のように定義します。

    @Bean(name="txName")
    public HibernateTransactionManager txName() throws IOException{
        HibernateTransactionManager txName= new HibernateTransactionManager();
        txName.setSessionFactory(...);
        txName.setDataSource(...);
        return txName;
   }

その上で、トランザクションジョブを実行するクラス/メソッドで、次のように注釈を付けます。

@Transactional("txName")

または

@Transactional(value = "txName")

これは、必要な場所に名前修飾トランザクションマネージャを結び付ける方法です。これで、必要な数のトランザクションマネージャを作成し、必要に応じて使用できます。

34
Angad

誰かがこの問題に遭遇した場合に備えて、解決策を見つけました:

@Configuration
@EnableTransactionManagement
@DependsOn("myTxManager")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements TransactionManagementConfigurer {

@Autowired
private PlatformTransactionManager myTxManager;

...

@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
    return this.myTxManager;
}

このようにして、xml構成で定義された特定のtxManagerを使用できます。

サービスレベルで使用されるtxManagerを定義する場合、removeからの@EnableTransactionManagementアノテーション@Configurationクラスと@TransactionalアノテーションでtxManagerを指定します。例えば.

@Service
@Transactional(value="myTxManager", readOnly = true)
public class MyServiceImpl implements MyService { ... }
8
Sleeper9

Java doc から

より直接的な関係を確立したい方のために
@EnableTransactionManagementおよび使用する正確なトランザクションマネージャBean、TransactionManagementConfigurerコールバックインターフェイスを実装できます-implements句と@Override-以下の注釈付きメソッド:

きみの @ConfigurationクラスはTransactionManagementConfigurerインターフェイスを実装する必要があります-使用するannotationDrivenTransactionManagerへの参照を返すtransactionManagerを実装します。

5
gkamal

2つのTransactionManagerを使用している理由がわかりません。 AbstractRoutingDataSourceを介して、複数のデータソースに同じTransactionManagerを使用することを検討できます。ご参照ください

http://blog.springsource.org/2007/01/23/dynamic-datasource-routing/

その使用法のサンプル。

1
Aravind A

他の回答のいくつかは、2つのトランザクションマネージャーを使用することが何らかの形で間違っていることを暗示しています。ただし、SpringのXML構成では、オンラインドキュメント(下記)に記載されているように、複数のトランザクションマネージャーを使用できます。残念ながら、@EnableTransactionManagementアノテーションを同様の方法で機能させる方法はないようです。その結果、@ImportResourceアノテーションを使用して、<tx:annotation-driven/>行を含むXMLファイルをロードするだけです。これにより、ほとんどの場合にJava構成を取得できますが、オプションのTransaction Manager修飾子とともに@Transactionalを引き続き使用できます。

http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/transaction.html

ほとんどのSpringアプリケーションに必要なトランザクションマネージャーは1つだけですが、単一のアプリケーションに複数の独立したトランザクションマネージャーが必要な場合があります。 @Transactionalアノテーションのvalue属性を使用して、使用するPlatformTransactionManagerのIDをオプションで指定できます。これは、トランザクションマネージャBeanのBean名または修飾子値のいずれかです。たとえば、修飾子表記を使用すると、次のJavaコード

0
Brian D

chained TransactionalManagerを使用してみてください

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
public class ChainedDBConfig {

    @Bean("chainedTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("database1TransactionManager") final PlatformTransactionManager db1PlatformTransactionManager,
            @Qualifier("database2TransactionManager") final PlatformTransactionManager db2PlatformTransactionManager) {

        return new ChainedTransactionManager(db1PlatformTransactionManager, db2PlatformTransactionManager);
    }

}

そして、次の注釈をサービスクラスに配置します。

@Transactional(transactionManager = "chainedTransactionManager")
public class AggregateMessagesJobIntegrationTest {
   ...
}

統合テスト内でも使用できます。

@RunWith(SpringRunner.class)
@Transactional(transactionManager = "chainedRawAndAggregatedTransactionManager")
@Rollback
public class ExampleIntegrationTest extends AbstractIntegrationTest {
    ....
}

また、両方のDBトランザクションマネージャーに対してロールバックを実行します。

0
Leonid Dashko