SpringBoot整合Dubbo LCN進行分散式事務管理
前言
在之前的spring+dubbo進行分散式專案搭建時,在面對被@Transactionnal()註解的事務服務時,dubbo是不能將其註冊成服務者的。
查閱資料後發現大致原因:是因為我們一般的service釋出dubbo服務時,dubbo能夠掃描到類上dubbo的@service註解,併為其生成代理,而當我們使用@Transactionnal註解時,將會採用cglib為service生成代理,生成的類為原service的子類,而bubbo並沒有允許子類繼承父類的註解,因此就掃描不到這個註解並生成代理了。
解決方法可參考部落格:http://blog.csdn.net/verne_feng/article/details/53022088
背景
在事務成功註冊上之後,遠端多資料庫跨服務跨庫回滾成為亟待解決的難題。參考大量資料後發現,這是一個通用的世界性難題,而向阿里騰訊一些大團隊,他們應用的也無非是使用以下兩中方式結合使用:
1、使用各種MQ訊息中介軟體進行事務代理,涉及事務問題多采用兩段式或三段式提交,並儘量將事務拆分成本地事務序列。
2、使用本地訊息庫進行訊息儲存,因為訊息中介軟體具有一定的不可靠性,所以使用本地庫作為一種彌補。
首先呢,通過多方調研,我們不可否認,上述做法具有其特定的優越性。因為從大資料量、高併發以及億級使用者壓力角度來講。上述方式也許是唯一一種比較可行的方式。
但結合我們的實際環境和需求,上述方式並不能解決我們對事務的完整回滾操作。後經過調研發現DUBBO LCN可以完成這項使命。DUBBO LCN是將我們的事務進行標註,形成一個事務組,當我們需要回滾的時候,控制事務組回滾即可。這樣將一個個子事務的回滾交給其所在的資料庫,由資料庫單獨執行回滾。可行性很高。
當然,同樣站在使用者壓力角度看,我猜想LCN可能並不能承受很高的壓力,因為每次我們都需要標註事務,形成事務組,當事務鏈又多又長的時候,其效能可以想象,肯定高不了。但是站在我們當前的小站點來說,當用戶壓力並不足以造成巨大的影響時,使用LCN將是我們的首選。因為其簡潔明瞭,只需要在本地事務上將本地事務標註為tx-manager事務,新增或生成事務組即可。
配置
在明白了LCN的背景及其作用域後,我們開始配置環境。
1、下載工具
如果你需要一個直接配置好的成品開箱即用,你可以下載筆者整理好的包,按readme.txt的描述啟動即可。
另外所需本地環境需自行下載:
zookeeper
redis
2、配置解析
參考官網配置,這裡做出解釋:
在LcnConfg.java中,我們添加了如下註解:
@Configuration
@EnableTransactionManagement(proxyTargetClass=true)
@ComponentScan(basePackages={"com.codingapi.tx.*","com.iking.provider.*"})
@ImportResource(locations = {"classpath*:dubbo_provider.xml"})
public class LcnConfig implements TxManagerTxUrlService{
@Autowired
private Environment env;
/**
* 獲取代理連線池
* @return
*/
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
/**
* 注入LCN的代理連線池
* @return
*/
@Bean("transactionManager")
public PlatformTransactionManager txManager(){
return new DataSourceTransactionManager(dataSource());
}
@Override
public String getTxUrl() {
return env.getProperty("tx.manager.url");
}
}
1)首先呢,我們將此類標註為全域性配置類,使用@Configuration
2)我們使用@EnableTransactionManagement(proxyTargetClass=true)開啟事務遠端代理,並進行連線池和LCN代理的注入:
@Autowired
private Environment env;
/**
* 獲取代理連線池
* @return
*/
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
/**
* 注入LCN的代理連線池
* @return
*/
@Bean("transactionManager")
public PlatformTransactionManager txManager(){
return new DataSourceTransactionManager(dataSource());
}
這個註解等同於官網上xml中的下列程式碼:
<!--lcn代理連線池配置-->
<bean name="lcnDataSourceProxy" class="com.lorne.tx.db.LCNDataSourceProxy">
<property name="dataSource" ref="dataSource"/>
<!-- 分散式事務參與的最大連線數,確保不要超過普通連線池的最大值即可 -->
<property name="maxCount" value="20"/>
</bean>
<!--jdbcTemplate -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="lcnDataSourceProxy"/>
</property>
</bean>
<!--jdbc事務配置 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="lcnDataSourceProxy" />
</bean>
以及:
<tx:annotation-driven/>
<!-- Aspect -->
<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>
3)使用@ComponentScan(basePackages={“com.codingapi.tx.“,”com.iking.provider.“})掃描lcn以及本專案相關路徑,等同於官網demo中的:
<context:component-scan base-package="com.codingapi.tx.*"/>
4)最後,我們實現了TxManagerTxUrlService介面,將tx-manager的路徑進行自定義配置:
public class LcnConfig implements TxManagerTxUrlService{
@Override
public String getTxUrl() {
return env.getProperty("tx.manager.url");
}
application.properties中新增路徑配置即可:
#tx-manager
tx.manager.url=http://127.0.0.1:8899/tx/manager/
5)最後,我們將dubbo_provider.xml引進來:
@ImportResource(locations = {"classpath*:dubbo_provider.xml"})
等同於官網上的下列配置:
配置介紹到此為止,即可進行測試,如有疑問,煩請@筆者:[email protected]