- Transaction Manager for Microservices Developer Guide
- Develop Applications with XA
- Develop Spring REST Apps with XA
- Configure Spring REST App as Transaction Participant
- Configure JPA-Based Spring REST Apps with XA-Compliant Resource Manager
6.10.3.5 Configure JPA-Based Spring REST 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 REST applications 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: trueEnsure that
xa-xa-supportis set totrue.For details about each property and other optional properties, see Configure Library Properties for Spring REST Apps.
- Include only one of the following MicroTx library files as a maven dependency in the Spring Boot 3.x application's
pom.xmlfile. The following sample code is for the 24.2 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-starterfile.<dependency> <groupId>com.oracle.microtx</groupId> <artifactId>microtx-spring-boot-starter</artifactId> <version>24.2</version> </dependency> -
For Java Apps that use Hibernate as JPA provider, use the
microtx-spring-boot-starter-hibernatelibrary file.<dependency> <groupId>com.oracle.microtx</groupId> <artifactId>microtx-spring-boot-starter-hibernate</artifactId> <version>24.2</version> </dependency> -
For Java Apps that use EclipseLink as JPA provider, use the
microtx-spring-boot-starter-eclipselinklibrary file.<dependency> <groupId>com.oracle.microtx</groupId> <artifactId>microtx-spring-boot-starter-eclipselink</artifactId> <version>24.2</version> </dependency>
-
- Create a
.javafile in the folder that contains your application code to initialize anXADataSourceConfigobject. TheXADataSourceConfigclass 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 REST shows how you can initialize the library in within the
XADataSourceConfigclass, 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.HibernateXADataSourceConnectionProvideras 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 REST shows how you can initialize the library in within the
PoolXADataSourceclass, 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_CONNECTORandPersistenceUnitProperties.SESSION_EVENT_LISTENER_CLASSproperties 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,
emfis 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,
emfis the entity manager factory object that you have created, and then you pass it to the MicroTx library.departmentDataSourceis the name of the data source that you have created in the above sample code before callingMicroTxConfig.initEntityManagerFactory().ORCL1-8976-9776-9873is 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
connectionobject that is created by the MicroTx client library.-
If you use a single resource manager with a single application, inject an
EntityManagerobject as shown in the following code sample, wheremicroTxEntityManageris 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
EntityManagerobject 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,
microTxEntityManageris the entity manager factory object anddepartmentDataSourceandcreditDataSourceare 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 ascreditDataSourcein 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 REST App as Transaction Participant