I. Overview
1. Business background
The reconstruction of the old system combined, resulting in the new system needs to manage 3 databases at the same time. Because of cross-library business, distributed transactions need to be implemented.
2. Development environment
Spring Framework version 4.3.10.RELEASE
The persistence layer is a domain model written in conjunction with MyBatis, such as
Each entity corresponds to a table of the database, @DataSource annotation (custom) of the corresponding data source key value. So there may be a switchover of the data source in a business.
Transactions are driven by annotated @transaction.
Second, spring support for multiple data sources
The spring framework implements multi-data source support through abstract class Abstractroutingdatasource.
There is an abstract method Determinecurrentlookupkey () in Abstractroutingdatasource. Subclasses implement this method.
Examples are as follows:
PackageCom.cmcc.cq.xx.common.mybatis;ImportOrg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; Public classDynamicdatasourceextendsAbstractroutingdatasource {@OverrideprotectedObject Determinecurrentlookupkey () {returnGetdatasourcetype (); } Private Static FinalThreadlocal<string> Contextholder =NewThreadlocal<string>(); Public Static voidSetdatasourcetype (String datasourcetype) {contextholder.set (datasourcetype); } Public StaticString Getdatasourcetype () {returnContextholder.get (); } Public Static voidCleardatasourcetype () {contextholder.remove (); }}
Threadlocal saves the current thread's data source, and before performing the database operation, it sets the data source type of the next operation by parsing the annotation @datasource, which is the corresponding key value (see following data source configuration).
In this case, a multi-data source switchover can be done without the use of transactions.
Third, spring distributed transaction support
1. Datasourcetransactionmanager does not support multiple data sources
The Datasourcetransactionmanager transaction manager is a single data source transaction manager that injects a data source when it is instantiated.
<bean name= "TransactionManager" class= "Org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name= "DataSource" ref= "Dynamicdatasource" ></property>
</bean>
Note: Although we inject a dynamic data source, Datasourcetransactionmanager does not change because we use Dynamic Data sources.
Because Datasourcetransactionmanager gets the database connection when it starts a transaction, it is not always obtained through DataSource, usually through the Connectionholder class.
Therefore, the open transaction will report an exception for the table or view.
At the same time, Datasourcetransactionmanager can not achieve the consistency of cross-database transaction.
2. Jtatransactionmanager supports distributed transactions
The Jtatransactionmanager transaction manager only provides an access method, and does not do the corresponding implementation, the current more popular third-party implementation of distributed transactions is Atomikos and JOTM. Where the JOTM update date is 2010, it is recommended to use Atomikos.
The two configurations are similar, taking Atomikos as an example.
Introducing MAVEN Dependencies
<dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jdbc< /artifactid> <version>3.7.0</version> </dependency>
The first is the configuration of the data source, the class Com.atomikos.jdbc.AtomikosDataSourceBean must be used, and no other connection pool overrides can be used. Xadatasourceclassname to select the appropriate class according to the database, in the database corresponding to the driver package can be found.
<bean id= "DataSource3" class= "Com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method= "Close" > <property Name= "Uniqueresourcename" value= "Key Value"/> <property name=" xadatasourceclassname "value=" Oracle.jdbc.xa.client.OracleXADataSource "/> <prope Rty name= "Xaproperties" > <props> <prop key= "URL" >${jdbc.dataSource.url3}</prop> <prop key= "User" >${jdbc.dataSource.username3}</prop> <prop key= "password" >${j dbc.datasource.password3}</prop> </props> </property> <property name= "Minpoolsize" Value= "${jdbc.datasource.minimumidle3}"/> <property name= "maxpoolsize" value= "${ Jdbc.dataSource.maximumPoolSize3} "/> <property name=" borrowconnectiontimeout "value=" ${ JDBC.DATASOURCE.CONNECTIONTIMEOUT3} "/> <property name=" testquery "value=" ${ Jdbc.dataSource.connectionTestQuery3} "/> <property name=" maintenanceinterval "value="/> <proper Ty name= "MaxIdleTime" value= "${jdbc.datasource.idletimeout3}" ></property></bean>
Then the Jtatransactionmanager transaction manager configuration.
Jtatransactionmanager has two important properties that need to be configured for TransactionManager and usertransaction. The corresponding configuration classes are as follows:
Note: You only need to configure the TransactionManager property in Jotm
Finally, the Atomikos configuration file jta.properties.
Configuration path: Root path
Jta.properties can also be named Transactions.properties, and if you do not configure it, start the project because almost all configuration items have default values.
Transactions.properties Configuration
Analysis and solution of Spring Multi-data source distributed transaction