- Transaction Manager for Microservices開発者ガイド
- XAでのアプリケーションの開発
- XAでのSpring Bootアプリケーションの開発
- トランザクション参加側としてのSpring Bootアプリケーションの構成
- XA準拠リソース・マネージャを使用するJPAベースのSpring Bootアプリケーションの構成
7.10.3.5 XA準拠リソース・マネージャを使用するJPAベースのSpring Bootアプリケーションの構成
XA準拠のリソース・マネージャを使用する場合は、この項に記載されている情報を使用して、XAトランザクションに参加するHelidonまたはSpring BootアプリケーションのJPAプロバイダとしてHibernateまたはEclipseLinkを構成します。
- 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-support
がtrue
に設定されていることを確認します。各プロパティおよびその他のオプション・プロパティの詳細は、「Spring Bootアプリケーションのライブラリ・プロパティの構成」を参照してください。
- 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>
-
- 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); }
- アプリケーション・コードを含むフォルダに
.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; } }
-
- エンティティ・マネージャ・ファクトリ・オブジェクトを初期化するには、アプリケーションが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)です。
-
- 参加側サービスのコードに次の行を挿入して、アプリケーションが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
などの他のリソース・マネージャの情報を指定します。すべてのリソース・マネージャについてこのステップを繰り返します。
-
- アプリケーション・コードで、MicroTxライブラリに渡したエンティティ・マネージャ・オブジェクトを注入します。ビジネス・ロジックに基づいてアプリケーション・コード内でエンティティ・マネージャ・オブジェクトを使用し、このオブジェクトを使用してデータベースに接続します。
- 変更内容を保存します。
MicroTxライブラリおよびHibernateをJPAプロバイダとして使用するサンプルSpring RESTトランザクション参加側アプリケーションのソース・コードは、department-spring-jpa
フォルダにあります。MicroTxライブラリおよびEclipseLinkをJPAプロバイダとして使用するサンプルSpring RESTトランザクション参加側アプリケーションのソース・コードは、department-spring-jpa-eclipselink
フォルダにあります。MicroTxライブラリをアプリケーションと統合する際の参照として、microtx-samples
GitHubリポジトリにあるソース・コードを使用します。