分布式事務解決方案 - Seata 使用樣例
Seata Server端環境准備
(1)從官網上下載seata server端的程序包
下載地址:https://github.com/seata/seata/releases
(2)修改配置
我們是基於file的方式啟動注冊和承載配置的

打開conf/file.conf文件
修改service 節點目錄內容如下:
service {
#vgroup->rgroup
vgroup_mapping.my_test_tx_group = "default"
#only support single node
default.grouplist = "127.0.0.1:8091"
#degrade current not support
enableDegrade = false
#disable
disable = false
#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
max.commit.retry.timeout = "-1"
max.rollback.retry.timeout = "-1"
}
說明:需要修改default.grouplist = “127.0.0.1:8091”,將該值設置為seata server向外提供服務ip及端口(或域名+端口)
(4)啟動server
到bin目錄下執行腳本啟動seata server端,注:windows下執行seata-server.bat啟動;linux下執行seata-server.sh啟動
2.4 項目集成seata
2.4.1 創建日志表undo_log
分別在leadnews_article、leadnews_user、leadnews_wemedia三個庫中都創建undo_log表
2.4.2 導入依賴包
因為有多個工程都需要引入seata,所以新建一個工程heima-leadnews-seata專門來處理分布式事務
<dependencies>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-common</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>0.9.0</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
</dependencies>
2.4.3 創建代理數據源
(1)因為多個工程都需要依賴與seata,所以在heima-leadnews-seata模塊下創建seata的配置類
package com.heima.seata.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import io.seata.rm.datasource.DataSourceProxy;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@EnableConfigurationProperties({MybatisPlusProperties.class})
public class DataSourcesProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
return new DruidDataSource();
}
//創建代理數據源
@Primary//@Primary標識必須配置在代碼數據源上,否則本地事務失效
@Bean
public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
private MybatisPlusProperties properties;
public DataSourcesProxyConfig(MybatisPlusProperties properties) {
this.properties = properties;
}
//替換SqlSessionFactory的DataSource
@Bean
public MybatisSqlSessionFactoryBean sqlSessionFactory(DataSourceProxy dataSourceProxy, PaginationInterceptor paginationInterceptor) throws Exception {
// 這里必須用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否則 MyBatisPlus 不會生效
MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
mybatisSqlSessionFactoryBean.setDataSource(dataSourceProxy);
mybatisSqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
mybatisSqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:/mapper/*.xml"));
MybatisConfiguration configuration = this.properties.getConfiguration();
if(configuration == null){
configuration = new MybatisConfiguration();
}
mybatisSqlSessionFactoryBean.setConfiguration(configuration);
//設置分頁
Interceptor[] plugins = {paginationInterceptor};
mybatisSqlSessionFactoryBean.setPlugins(plugins);
return mybatisSqlSessionFactoryBean;
}
}
(2)分別在heima-leadnews-article、heima-leadnews-user、heima-leadnews-wemedia引入heima-leadnews-seata工程,並且添加一下配置類:
@Configuration
@ComponentScan("com.heima.seata.config")
public class SeataConfig {
}
2.4.4 配置seata-server鏈接和注冊中心信息
修改注冊中心配置,在每個項目中必須按照下方要求來
將配置文件file.conf和配置文件register.conf放到每個需要參與分布式事務項目的resources中。
- file.conf中的service.default.grouplist修改成seata-server的IP地址file.conf中的
- service.vgroup_mapping.xxx改成vgroup_mapping.#{spring.application.name}_tx_group = “default”
特別注意:#{spring.application.name}是一個變量,指的是該項目的名稱
如自媒體微服務名稱的項目名稱如下:

那么其配置就是vgroup_mapping.leadnews-wemedia_tx_group = "default"
其他項目也是這么依次配置
2.4.5 指定事務分組
分別在heima-leadnews-article、heima-leadnews-user、heima-leadnews-wemedia微服務的application.yml文件中添加如下配置:
spring:
cloud:
alibaba:
seata:
tx-service-group: ${spring.application.name}_tx_group
2.4.6 在分布式事務控制方法上添加注解@GlobalTransactional
在ApUserRealnameServiceImpl類的updateStatusById方法上加上@GlobalTransactional注解
2.4.7 啟動seata-server
運行:/seata/bin/seata-server.bat

2.4.8 測試
(1)功能測試,看功能能否正常執行。
(2)異常測試,我們在方法中添加int x=1/0 ,看認證信息和自媒體用戶是否能夠回滾。

