1. 程式人生 > >SpringBoot整合Dubbo LCN進行分散式事務管理

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]