- Transaction Manager for Microservices Developer Guide
- Develop Applications with XA
- Develop Spring Boot Apps with XA
- Configure Spring Boot App as Transaction Participant
- Configure JPA-Based Spring Boot Apps with XA-Compliant Resource Manager
7.10.3.5 Configure JPA-Based Spring Boot Apps with XA-Compliant Resource Manager
Use the information provided in this section to configure Hibernate or EclipseLink as the JPA provider for your Helidon or Spring Boot application which participates in an XA transaction when you use an XA-compliant resource manager.
- Configure property values for the MicroTx client library.
The following example provides sample values for the properties. Provide the values based on your environment.
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
Ensure that
xa-xa-support
is set totrue
.For details about each property and other optional properties, see Configure Library Properties for Spring Boot Apps.
- Include MicroTx library files as a maven dependency in the Spring Boot 3.x application's
pom.xml
file. The following sample code is for the 24.4 release. Provide the correct version, based on the release version that you want to use. Spring Boot 3.x applications work with Java 17.-
For JDBC applications, use the
microtx-spring-boot-starter
file.<dependency> <groupId>com.oracle.microtx</groupId> <artifactId>microtx-spring-boot-starter</artifactId> <version>24.4</version> </dependency>
-
When Hibernate is the JPA provider, use the
microtx-spring-boot-starter
andmicrotx-spring-boot-starter-hibernate
files.<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>
-
When EclipseLink is the JPA provider, use the
microtx-spring-boot-starter
andmicrotx-spring-boot-starter-eclipselink
files.<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>
-
For JDBC applications, use the
microtx-spring-boot-jaxrs-starter
file.<dependency> <groupId>com.oracle.microtx</groupId> <artifactId>microtx-spring-boot-jaxrs-starter</artifactId> <version>24.4</version> </dependency>
-
When Hibernate is the JPA provider, use the
microtx-spring-boot-jaxrs-starter
andmicrotx-spring-boot-starter-hibernate
files.<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>
-
When EclipseLink is the JPA provider, use the
microtx-spring-boot-jaxrs-starter
andmicrotx-spring-boot-starter-eclipselink
files.<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>
-
- Only for Spring JAX-RS applications, you must register the following filters so that the MicroTx library can intercept the JAX-RS calls and manage the transaction. You can skip this step for Spring REST applications.
import org.glassfish.jersey.server.ResourceConfig; ... @Component public class Configuration extends ResourceConfig { public Configuration() { ... register(TrmTransactionRequestFilter.class); register(TrmTransactionResponseFilter.class); register(JaxRsXACallbackResource.class); }
- Create a
.java
file in the folder that contains your application code to initialize anXADataSourceConfig
object. TheXADataSourceConfig
class contains methods to create custom data source and entity manager factory objects.The custom data source object contains details to connect with the resource manager. It is the responsibility of the application developer to ensure that an XA-compliant JDBC driver and required parameters are set up while creating a custom data source object.
-
The following example code for Hibernate apps using Spring Boot shows how you can initialize the library in within the
XADataSourceConfig
class, create a custom data source nameddepartmentDataSource
, and create an entity manager factory object namedemf
. You can create a similar code for your application.Ensure that you specify
com.oracle.microtx.jpa.HibernateXADataSourceConnectionProvider
as the property value forhibernate.connection.provider_class
.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; } }
-
The following example code for EcpliseLink apps using Spring Boot shows how you can initialize the library in within the
PoolXADataSource
class, create a custom data source nameddepartmentDataSource
, and create an entity manager factory object namedemf
. You can create a similar code for your application.Ensure that you specify values for the
PersistenceUnitProperties.JDBC_CONNECTOR
andPersistenceUnitProperties.SESSION_EVENT_LISTENER_CLASS
properties exactly as mentioned in the following sample code.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; } }
-
- To initialize the Entity Manager Factory object, pass the required parameters to
MicroTxConfig.initEntityManagerFactory()
based on whether your application connects to a single resource manager or multiple resource managers.-
When your application connects to a single resource manager, create an entity manager factory object and then pass it to the MicroTx library. In the following sample code,
emf
is the name of the entity manager factory object.MicroTxConfig.initEntityManagerFactory(emf);
-
When your application connects with multiple resource managers, you must pass the following parameters while calling
MicroTxConfig.initEntityManagerFactory()
.MicroTxConfig.initEntityManagerFactory(emf, departmentDataSource, ORCL1-8976-9776-9873);
Where,
emf
is the entity manager factory object that you have created, and then you pass it to the MicroTx library.departmentDataSource
is the name of the data source that you have created in the above sample code before callingMicroTxConfig.initEntityManagerFactory()
.ORCL1-8976-9776-9873
is the resource manager ID (RMID).
-
- Insert the following lines in the code of the participant service so that the application uses the connection passed by the MicroTx client library. The following code in the participant application injects the
connection
object that is created by the MicroTx client library.-
If you use a single resource manager with a single application, inject an
EntityManager
object as shown in the following code sample, wheremicroTxEntityManager
is the name of the entity manager factory object.@Autowired @Qualifier("microTxEntityManager") @Lazy private EntityManager entityManager;
-
When you use multiple resource managers with your application, inject an
EntityManager
object for every resource manager as shown in the following code sample.//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()); } }
Where,
microTxEntityManager
is the entity manager factory object anddepartmentDataSource
andcreditDataSource
are data source objects that you have created in the previous step. The earlier code sample provides details aboutdepartmentDataSource
. Provide information for other resource managers, such ascreditDataSource
in a similar way.Repeat this step for every resource manager.
-
- In your application code, inject the entity manager object that you have passed to the MicroTx library. Use the entity manager object in your application code based on your business logic, and then use this object to connect to the database.
- Save the changes.
Source code of a sample Spring REST transaction participant application which uses the MicroTx library and Hibernate as the JPA provider is available in the department-spring-jpa
folder. Source code of a sample Spring REST transaction participant application which uses the MicroTx library and EclipseLink as the JPA provider is available in the department-spring-jpa-eclipselink
folder. Use the source code, which is available in the microtx-samples
GitHub repository, as a reference while integrating the MicroTx libraries with your application.
Parent topic: Configure Spring Boot App as Transaction Participant