spring-boot入門(七)atomikos+druid+多資料來源下的分散式事務配置
spring-boot入門(七)atomikos+druid+多資料來源下的分散式事務配置
本章內容是基於spring-boot入門(六)多資料來源的基礎之上進行的,如果還不瞭解多資料來源怎麼配置,請參考上一章節的內容。在上一章節的末尾我們遺留了一個問題:多資料來源下的分散式事務問題。在分散式事務下我們需要使用JTA(Java Transaction API)事務來處理事務,保證事務的強一致性,即要成功都成功,一個失敗全部回滾。Atomikos 是一個為Java平臺提供增值服務的並且開源類事務管理器,本章我們將使用Atomikos 來解決分散式事務問題。
1. 配置atomikos
JTA事務的配置需要配置:XA資料來源和JTA事務管理器
1.1 引入atomikos依賴
spring boot整合atomikos,只需新增一下依賴即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
1.2 自定義atomikos相關屬性(自動注入JTA事務管理器)
如果不自定義相關屬性,那麼spring boot 會初始化預設的atomikos配置,可看org.springframework.boot.autoconfigure.transaction.jta.AtomikosJtaConfiguration是如何初始化預設的配置。當然也可以自定義atomikos,通過該配置spring boot會啟用atomikos實現的JTA事務管理器。
spring:
jta:
atomikos:
properties:
max-actives: 50
max-timeout: 300000
default-jta -timeout: 10000
enable-logging: true
上面是atomikos的一個配置示例。更多可檢視org.springframework.boot.jta.atomikos.AtomikosProperties。
1.3 配置XA資料來源
@Bean
@Primary
@ConfigurationProperties(prefix = "boc.datasource")
public DataSource bocDataSource(@Qualifier("bocDataSourceProperties") DataSourceProperties dataSourceProperties) throws SQLException {
DruidXADataSource druidXADataSource = new DruidXADataSource();
InitDruidDataSource(druidXADataSource, dataSourceProperties);
AtomikosDataSourceBean atomikosDataSource = new AtomikosDataSourceBean();
atomikosDataSource.setUniqueResourceName("bocDataSource");
atomikosDataSource.setXaDataSource(druidXADataSource);
atomikosDataSource.setTestQuery("SELECT 1");
return atomikosDataSource;
}
@Bean
@ConfigurationProperties(prefix = "ccb.datasource")
public DataSource ccbDataSource(@Qualifier("ccbDataSourceProperties") DataSourceProperties dataSourceProperties) throws SQLException {
DruidXADataSource druidXADataSource = new DruidXADataSource();
InitDruidDataSource(druidXADataSource, dataSourceProperties);
//也可以使用mysql預設的xa資料來源
//MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
//mysqlXADataSource.setUrl(dataSourceProperties.getUrl());
//mysqlXADataSource.setUser(dataSourceProperties.getUsername());
//mysqlXADataSource.setPassword(dataSourceProperties.getPassword());
AtomikosDataSourceBean atomikosDataSource = new AtomikosDataSourceBean();
atomikosDataSource.setUniqueResourceName("ccbDataSource");
atomikosDataSource.setXaDataSource(druidXADataSource);
atomikosDataSource.setTestQuery("SELECT 1");
return atomikosDataSource;
}
在這裡我們返回的是AtomikosDataSourceBean ,是Druid實現的一個XA資料來源也可以用註釋中的MysqlXADataSource,配置了XAdatasource還需要將其轉換為AtomikosDataSourceBean(Atomikos使用的是該資料來源,用於包裝不同的XA資料來源實現,使得底層架構不變,對擴充套件開放),springboot預設配置的時候會使用AtomikosXADataSourceWrapper來包裹XAdatasource:
因為我們是手動注入DataSource,所以需要自己重新包裝一次。
到此XA資料來源和JTA事務都配置完畢,這時使用@Transactional註解將使用atomikos實現的事務管理器。
2.測試
還是沿用上節的測試程式碼,當我們執行testTransferAccountCcbToBocOnException()測試方法,會發現ccb庫的資料成功回滾。而且根據console日誌能檢視事務提交和回滾的完整過程:
2018-04-02 23:15:49.536 INFO 14076 --- [ main] c.a.icatch.imp.BaseTransactionManager : createCompositeTransaction ( 10000 ): created new ROOT transaction with id 10.100.144.36.tm0000100001
2018-04-02 23:15:49.574 INFO 14076 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'ccbDataSource': getConnection ( null )...
2018-04-02 23:15:49.574 INFO 14076 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'ccbDataSource': init...
2018-04-02 23:15:49.628 INFO 14076 --- [ main] c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:49.628 INFO 14076 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 , XAResource.TMNOFLAGS ) on resource ccbDataSource represented by XAResource instance [email protected]
2018-04-02 23:15:49.689 INFO 14076 --- [ main] c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.a[email protected]a9775fbb ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:49.689 INFO 14076 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for [email protected]: calling prepareStatement(UPDATE account_ccb SET balance = balance+? WHERE customer = ?;)...
2018-04-02 23:15:50.358 INFO 14076 --- [ main] c.f.service.impl.AccountCcbServiceImpl : update balance ,[customer:10002,amount:-100]
2018-04-02 23:15:50.364 INFO 14076 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'bocDataSource': getConnection ( null )...
2018-04-02 23:15:50.364 INFO 14076 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'bocDataSource': init...
2018-04-02 23:15:50.367 INFO 14076 --- [ main] c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:50.374 INFO 14076 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 , XAResource.TMNOFLAGS ) on resource bocDataSource represented by XAResource instance [email protected]
2018-04-02 23:15:50.379 INFO 14076 --- [ main] c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.a[email protected]a9775fbb ) for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:50.379 INFO 14076 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for [email protected]: calling prepareStatement(UPDATE account_boc SET balance = balance+? WHERE customer = ?;)...
2018-04-02 23:15:50.451 INFO 14076 --- [ main] c.a.icatch.imp.CompositeTransactionImp : setRollbackOnly() called for transaction 10.100.144.36.tm0000100001
2018-04-02 23:15:50.452 INFO 14076 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for [email protected]: close()...
2018-04-02 23:15:50.452 INFO 14076 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 , XAResource.TMSUCCESS ) on resource ccbDataSource represented by XAResource instance [email protected]
2018-04-02 23:15:50.453 INFO 14076 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for [email protected]: close()...
2018-04-02 23:15:50.453 INFO 14076 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 , XAResource.TMSUCCESS ) on resource bocDataSource represented by XAResource instance [email protected]
2018-04-02 23:15:50.456 INFO 14076 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.rollback ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D31 ) on resource ccbDataSource represented by XAResource instance [email protected]
2018-04-02 23:15:50.583 INFO 14076 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.rollback ( 31302E3130302E3134342E33362E746D30303030313030303031:31302E3130302E3134342E33362E746D32 ) on resource bocDataSource represented by XAResource instance [email protected]
2018-04-02 23:15:50.587 INFO 14076 --- [ main] c.a.icatch.imp.CompositeTransactionImp : rollback() done of transaction 10.100.144.36.tm0000100001
在上面的日誌中我們可以看到,當其中一個事務失敗,會JTA呼叫setRollbackOnly(),然後XAResource連線呼叫各自的rollback()方法進行回滾。
到本章為止,使用spring boot訪問資料庫,及多資料來源和多資料來源下的分散式事務都已經介紹完了,之後的章節可能會介紹如何使用攔截器和過濾器及其它的一些web應用中的常見技術在spring boot中的應用。
本章完整程式碼在:https://github.com/Json-Lin/spring-boot-practice/tree/master/spring-boot-practice-atomikos
END