7.10.3.5 XA準拠リソース・マネージャを使用するJPAベースのSpring Bootアプリケーションの構成

XA準拠のリソース・マネージャを使用する場合は、この項に記載されている情報を使用して、XAトランザクションに参加するHelidonまたはSpring BootアプリケーションのJPAプロバイダとしてHibernateまたはEclipseLinkを構成します。

アプリケーションは、複数のXA準拠リソース・マネージャに接続できます。アプリケーションで複数のXA準拠リソース・マネージャを使用している場合は、リソース・マネージャごとに次のステップを実行します。
  1. MicroTxクライアント・ライブラリのプロパティ値を指定します。

    次の例では、プロパティのサンプル値を指定しています。ご自身の環境に基づいて値を指定してください。

    spring:
      microtx:
        participant-url: https://bookTicket-app:8081
        propagation-active: true
        http-client-connection-pool-size: 15
        xa-transaction-timeout: 60000
        xa-resource-manager-id: 174A5FF2-D8B1-47B0-AF09-DA5AFECA2F61
        xa-xa-support: true
    

    xa-xa-supporttrueに設定されていることを確認します。

    各プロパティおよびその他のオプション・プロパティの詳細は、「Spring Bootアプリケーションのライブラリ・プロパティの構成」を参照してください。

  2. MicroTxライブラリ・ファイルをSpring Boot 3.xアプリケーションのpom.xmlファイルにmaven依存関係として含めます。次のサンプル・コードは24.4リリース用です。使用するリリース・バージョンに基づいて、正しいバージョンを指定してください。Spring Boot 3.xアプリケーションは、Java 17で動作します。
    • JDBCアプリケーションでは、microtx-spring-boot-starterファイルを使用します。

      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-starter</artifactId>
           <version>24.4</version>
      </dependency>
    • HibernateがJPAプロバイダの場合は、microtx-spring-boot-starterおよびmicrotx-spring-boot-starter-hibernateファイルを使用します。

      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-starter</artifactId>
           <version>24.4</version>
      </dependency>
      
      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-starter-hibernate</artifactId>
           <version>24.4</version>
      </dependency>
    • EclipseLinkがJPAプロバイダの場合は、microtx-spring-boot-starterおよびmicrotx-spring-boot-starter-eclipselinkファイルを使用します。

      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-starter</artifactId>
           <version>24.4</version>
      </dependency>
      
      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-starter-eclipselink</artifactId>
           <version>24.4</version>
      </dependency>
    • JDBCアプリケーションでは、microtx-spring-boot-jaxrs-starterファイルを使用します。

      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-jaxrs-starter</artifactId>
           <version>24.4</version>
      </dependency>
    • HibernateがJPAプロバイダの場合は、microtx-spring-boot-jaxrs-starterおよびmicrotx-spring-boot-starter-hibernateファイルを使用します。

      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-jaxrs-starter</artifactId>
           <version>24.4</version>
      </dependency>
      
      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-starter-hibernate</artifactId>
           <version>24.4</version>
      </dependency>
    • EclipseLinkがJPAプロバイダの場合は、microtx-spring-boot-jaxrs-starterおよびmicrotx-spring-boot-starter-eclipselinkファイルを使用します。

      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-jaxrs-starter</artifactId>
           <version>24.4</version>
      </dependency>
      
      <dependency>
           <groupId>com.oracle.microtx</groupId>
           <artifactId>microtx-spring-boot-starter-eclipselink</artifactId>
           <version>24.4</version>
      </dependency>
  3. Spring JAX-RSアプリケーションの場合のみ、MicroTxライブラリがJAX-RSコールをインターセプトしてトランザクションを管理できるように、次のフィルタを登録する必要があります。Spring RESTアプリケーションでは、このステップをスキップできます。
    import org.glassfish.jersey.server.ResourceConfig;
    ...
    @Component
    public class Configuration extends ResourceConfig {
        public Configuration() {
    ...
          register(TrmTransactionRequestFilter.class);
          register(TrmTransactionResponseFilter.class);
          register(JaxRsXACallbackResource.class);
    }
  4. アプリケーション・コードを含むフォルダに.javaファイルを作成して、XADataSourceConfigオブジェクトを初期化します。XADataSourceConfigクラスには、カスタム・データ・ソース・オブジェクトおよびエンティティ・マネージャ・ファクトリ・オブジェクトを作成するメソッドが含まれています。

    カスタム・データ・ソース・オブジェクトには、リソース・マネージャに接続するための詳細が含まれています。アプリケーション開発者は、カスタム・データ・ソース・オブジェクトを作成する際に、XA準拠JDBCドライバおよび必要なパラメータを設定する必要があります。

    • Spring Bootを使用するHibernateアプリケーションの次のコード例は、XADataSourceConfigクラス内のライブラリを初期化し、departmentDataSourceというカスタム・データ・ソースを作成し、emfというエンティティ・マネージャ・ファクトリ・オブジェクトを作成する方法を示しています。ご自身のアプリケーション用に同様のコードを作成できます。

      hibernate.connection.provider_classのプロパティ値としてcom.oracle.microtx.jpa.HibernateXADataSourceConnectionProviderが指定されていることを確認してください。

      package com.oracle.mtm.sample;
      
      import com.oracle.microtx.common.MicroTxConfig;
      import oracle.ucp.jdbc.PoolDataSourceFactory;
      import oracle.ucp.jdbc.PoolXADataSource;
      import org.hibernate.jpa.HibernatePersistenceProvider;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Primary;
      import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
      import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
      
      import javax.persistence.EntityManagerFactory;
      import javax.sql.DataSource;
      import javax.sql.XADataSource;
      import java.sql.SQLException;
      import java.util.Properties;
      
      @Configuration
      @ComponentScan("com.oracle")
      public class XADataSourceConfig {
          @Value("${departmentDataSource.url}")
          private String url;
          @Value("${departmentDataSource.user}")
          private String username;
          @Value("${departmentDataSource.password}")
          private String password;
          @Value("${departmentDataSource.oracleucp.min-pool-size}")
          private String minPoolSize;
          @Value("${departmentDataSource.oracleucp.initial-pool-size:10}")
          private String initialPoolSize;
      
          @Value("${departmentDataSource.oracleucp.max-pool-size}")
          private String maxPoolSize;
      
          @Value("${departmentDataSource.oracleucp.data-source-name}")
          private String dataSourceName;
      
          @Value("${departmentDataSource.oracleucp.connection-pool-name}")
          private String connectionPoolName;
      
          @Value("${departmentDataSource.oracleucp.connection-factory-class-name:oracle.jdbc.xa.client.OracleXADataSource}")
          private String connectionFactoryClassName;
      
          @Value("${spring.microtx.xa-resource-manager-id}")
          private String resourceManagerId;
      
          @Bean(name = "ucpXADataSource")
          @Primary
          public DataSource getDataSource() {
              DataSource pds = null;
              try {
                  pds = PoolDataSourceFactory.getPoolXADataSource();
      
                  ((PoolXADataSource) pds).setConnectionFactoryClassName(connectionFactoryClassName);
                  ((PoolXADataSource) pds).setURL(url);
                  ((PoolXADataSource) pds).setUser(username);
                  ((PoolXADataSource) pds).setPassword(password);
                  ((PoolXADataSource) pds).setMinPoolSize(Integer.valueOf(minPoolSize));
                  ((PoolXADataSource) pds).setInitialPoolSize(Integer.valueOf(initialPoolSize));
                  ((PoolXADataSource) pds).setMaxPoolSize(Integer.valueOf(maxPoolSize));
      
                  ((PoolXADataSource) pds).setDataSourceName(dataSourceName);
                  ((PoolXADataSource) pds).setConnectionPoolName(connectionPoolName);
      
                  System.out.println("XADataSourceConfig: XADataSource created");
              } catch (SQLException ex) {
                  System.err.println("Error connecting to the database: " + ex.getMessage());
              }
              return pds;
          }
      
      
          @Bean(name = "entityManagerFactory")
          public EntityManagerFactory createEntityManagerFactory() throws SQLException {
              LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
      
              entityManagerFactoryBean.setDataSource(getDataSource());
              entityManagerFactoryBean.setPackagesToScan(new String[] { "com.oracle.mtm.sample.entity" });
              entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
      
              entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
              entityManagerFactoryBean.setPersistenceUnitName("mydeptxads");
              Properties properties = new Properties();
              properties.setProperty( "javax.persistence.transactionType", "RESOURCE_LOCAL"); // change this to resource_local
              properties.put("hibernate.show_sql", "true");
              properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
              properties.put("hibernate.format_sql", "true");
              properties.put("hbm2ddl.auto", "validate");
              properties.put("hibernate.connection.provider_class", "com.oracle.microtx.jpa.HibernateXADataSourceConnectionProvider");
              entityManagerFactoryBean.setJpaProperties(properties);
              entityManagerFactoryBean.afterPropertiesSet();
              EntityManagerFactory emf = (EntityManagerFactory) entityManagerFactoryBean.getObject();
              System.out.println("entityManagerFactory = " + emf);
              MicroTxConfig.initEntityManagerFactory(emf, resourceManagerId); // Initialize TMM Library
              return emf;
          }
      }
    • Spring Bootを使用するEcpliseLinkアプリケーションの次のコード例は、PoolXADataSourceクラス内のライブラリを初期化し、departmentDataSourceというカスタム・データ・ソースを作成し、emfというエンティティ・マネージャ・ファクトリ・オブジェクトを作成する方法を示しています。ご自身のアプリケーション用に同様のコードを作成できます。

      次のサンプル・コードに記載されているとおりにPersistenceUnitProperties.JDBC_CONNECTORおよびPersistenceUnitProperties.SESSION_EVENT_LISTENER_CLASSプロパティの値が指定されていることを確認してください。

      package com.oracle.mtm.sample;
      
      import com.oracle.microtx.common.MicroTxConfig;
      import oracle.ucp.jdbc.PoolDataSourceFactory;
      import oracle.ucp.jdbc.PoolXADataSource;
      import org.eclipse.persistence.config.PersistenceUnitProperties;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.Primary;
      import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
      import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
      import org.eclipse.persistence.jpa.PersistenceProvider;
      
      import javax.persistence.EntityManagerFactory;
      import javax.sql.DataSource;
      import javax.sql.XADataSource;
      import java.sql.SQLException;
      import java.util.Properties;
      
      @Configuration
      @ComponentScan("com.oracle.microtx")
      public class XADataSourceConfig {
          @Value("${departmentDataSource.url}")
          private String url;
          @Value("${departmentDataSource.user}")
          private String username;
          @Value("${departmentDataSource.password}")
          private String password;
      
          @Value("${departmentDataSource.oracleucp.min-pool-size}")
          private String minPoolSize;
          @Value("${departmentDataSource.oracleucp.initial-pool-size:10}")
          private String initialPoolSize;
      
          @Value("${departmentDataSource.oracleucp.max-pool-size}")
          private String maxPoolSize;
      
          @Value("${departmentDataSource.oracleucp.data-source-name}")
          private String dataSourceName;
      
          @Value("${departmentDataSource.oracleucp.connection-pool-name}")
          private String connectionPoolName;
      
          @Value("${departmentDataSource.oracleucp.connection-factory-class-name:oracle.jdbc.xa.client.OracleXADataSource}")
          private String connectionFactoryClassName;
      
          @Value("${spring.microtx.xa-resource-manager-id}")
          private String resourceManagerId;
      
         @Bean(name = "ucpXADataSource")
          @Primary
          public DataSource getDataSource() {
              DataSource pds = null;
              try {
                  pds = PoolDataSourceFactory.getPoolXADataSource();
      
                  ((PoolXADataSource) pds).setConnectionFactoryClassName(connectionFactoryClassName);
                  ((PoolXADataSource) pds).setURL(url);
                  ((PoolXADataSource) pds).setUser(username);
                  ((PoolXADataSource) pds).setPassword(password);
                  ((PoolXADataSource) pds).setMinPoolSize(Integer.valueOf(minPoolSize));
                  ((PoolXADataSource) pds).setInitialPoolSize(Integer.valueOf(initialPoolSize));
                  ((PoolXADataSource) pds).setMaxPoolSize(Integer.valueOf(maxPoolSize));
      
                  ((PoolXADataSource) pds).setDataSourceName(dataSourceName);
                  ((PoolXADataSource) pds).setConnectionPoolName(connectionPoolName);
      
      
                  System.out.println("XADataSourceConfig: XADataSource created");
              } catch (SQLException ex) {
                  System.err.println("Error connecting to the database: " + ex.getMessage());
              }
              return pds;
          }
      
          @Bean(name = "entityManagerFactory")
          public EntityManagerFactory createEntityManagerFactory() throws SQLException {
              LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
      
              entityManagerFactoryBean.setDataSource(getDataSource());
              entityManagerFactoryBean.setPackagesToScan(new String[] { "com.oracle.mtm.sample.entity" });
              entityManagerFactoryBean.setJpaVendorAdapter(new EclipseLinkJpaVendorAdapter());
              entityManagerFactoryBean.setPersistenceProviderClass(PersistenceProvider.class);
              entityManagerFactoryBean.setPersistenceUnitName("mydeptxads");
      
              Properties properties = new Properties();
              properties.setProperty( "javax.persistence.transactionType", "RESOURCE_LOCAL"); // change this to resource_local
              properties.setProperty("javax.persistence.jdbc.driver", "oracle.jdbc.OracleDriver");
              properties.setProperty("javax.persistence.jdbc.url", url);
              properties.setProperty("javax.persistence.jdbc.user", username);
              properties.setProperty("javax.persistence.jdbc.password", password);
      
              properties.setProperty(PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false");
              properties.setProperty(PersistenceUnitProperties.TARGET_DATABASE, "Oracle");
              properties.setProperty(PersistenceUnitProperties.WEAVING, "false");
              properties.setProperty(PersistenceUnitProperties.JDBC_CONNECTOR, "com.oracle.microtx.eclipselink.EclipseLinkXADataSourceConnector");
              properties.setProperty(PersistenceUnitProperties.SESSION_EVENT_LISTENER_CLASS, "com.oracle.microtx.eclipselink.EclipseLinkXASessionEventAdaptor");
      
              entityManagerFactoryBean.setJpaProperties(properties);
              entityManagerFactoryBean.afterPropertiesSet();
              EntityManagerFactory emf = (EntityManagerFactory) entityManagerFactoryBean.getObject();
              System.out.println("entityManagerFactory = " + emf);
              MicroTxConfig.initEntityManagerFactory(emf, resourceManagerId); // Initialize TMM Library
              return emf;
          }
      }
  5. エンティティ・マネージャ・ファクトリ・オブジェクトを初期化するには、アプリケーションが1つのリソース・マネージャまたは複数のリソース・マネージャに接続するかに応じて、必要なパラメータをMicroTxConfig.initEntityManagerFactory()に渡します。
    • アプリケーションが1つのリソース・マネージャに接続する場合は、エンティティ・マネージャ・ファクトリ・オブジェクトを作成し、それをMicroTxライブラリに渡します。次のサンプル・コードで、emfはエンティティ・マネージャ・ファクトリ・オブジェクトの名前です。

      MicroTxConfig.initEntityManagerFactory(emf);
    • アプリケーションが複数のリソース・マネージャに接続する場合は、MicroTxConfig.initEntityManagerFactory()をコールするときに次のパラメータを渡す必要があります。

      MicroTxConfig.initEntityManagerFactory(emf, departmentDataSource, ORCL1-8976-9776-9873);

      説明

      • emfは、作成したエンティティ・マネージャ・ファクトリ・オブジェクトです。これをMicroTxライブラリに渡します。
      • departmentDataSourceは、前述のサンプル・コードでMicroTxConfig.initEntityManagerFactory()をコールする前に作成したデータ・ソースの名前です。
      • ORCL1-8976-9776-9873は、リソース・マネージャID (RMID)です。
  6. 参加側サービスのコードに次の行を挿入して、アプリケーションがMicroTxクライアント・ライブラリによって渡された接続を使用するようにします。参加側アプリケーションの次のコードは、MicroTxクライアント・ライブラリによって作成されたconnectionオブジェクトを注入します。
    • 1つのアプリケーションで1つのリソース・マネージャを使用する場合は、次のコード・サンプルに示すようにEntityManagerオブジェクトを注入します。ここで、microTxEntityManagerはエンティティ・マネージャ・ファクトリ・オブジェクトの名前です。

      @Autowired
      @Qualifier("microTxEntityManager")
      @Lazy
      private EntityManager entityManager;
    • アプリケーションで複数のリソース・マネージャを使用する場合は、次のコード・サンプルに示すようにリソース・マネージャごとにEntityManagerオブジェクトを注入します。

      //Initialize the application context
      private ApplicationContext applicationContext;
      //Entity Manager object for XA-compliant resource manager 1
      private EntityManager entityManager;
      //Entity Manager object for XA-compliant resource manager 2
      private EntityManager creditEntityManager;
      @Autowired
          public AccountService(ApplicationContext applicationContext) {
              this.applicationContext = applicationContext;
              try {
                  entityManager =  (EntityManager) applicationContext.getBean("microTxEntityManager", "departmentDataSource");
                  creditEntityManager =  (EntityManager) applicationContext.getBean("microTxEntityManager", "creditDataSource");
              } catch (ClassCastException ex) {
                  LOG.info(ex.getMessage());
              }
          }

      ここで、microTxEntityManagerはエンティティ・マネージャ・ファクトリ・オブジェクト、departmentDataSourceおよびcreditDataSourceは前のステップで作成したデータ・ソース・オブジェクトです。前のコード・サンプルは、departmentDataSourceの詳細を示しています。同様の方法で、creditDataSourceなどの他のリソース・マネージャの情報を指定します。

      すべてのリソース・マネージャについてこのステップを繰り返します。

  7. アプリケーション・コードで、MicroTxライブラリに渡したエンティティ・マネージャ・オブジェクトを注入します。ビジネス・ロジックに基づいてアプリケーション・コード内でエンティティ・マネージャ・オブジェクトを使用し、このオブジェクトを使用してデータベースに接続します。
  8. 変更内容を保存します。
複数のトランザクション参加側サービスがある場合は、すべての参加側サービスでこれらのステップを完了します。

MicroTxライブラリおよびHibernateをJPAプロバイダとして使用するサンプルSpring RESTトランザクション参加側アプリケーションのソース・コードは、department-spring-jpaフォルダにあります。MicroTxライブラリおよびEclipseLinkをJPAプロバイダとして使用するサンプルSpring RESTトランザクション参加側アプリケーションのソース・コードは、department-spring-jpa-eclipselinkフォルダにあります。MicroTxライブラリをアプリケーションと統合する際の参照として、microtx-samples GitHubリポジトリにあるソース・コードを使用します。