項目集成背景springCloud-eureka-feign-mybatis-seata
想更清楚的理解全局事務框架SeaTa,可以參考資料 https://www.jianshu.com/p/044e95223a17,我認為介紹的很詳細,下面來搭建集成並測試結果 參考:https://segmentfault.com/a/1190000020639849
一、安裝部署Seata Server
Seata
目前在github
托管開源源代碼,源碼地址:https://github.com/seata/seata
1.下載Seata Server
很多博客中文章中都給出了下載地址:Seata Server最新版本下載 https://github.com/seata/seata/releases/tag/v1.2.0 兩個安裝包,.zip支持Windows; .tar.gz支持Linux(這里下載的是1.2.0版本)
博主的百度雲盤有有存兩個1.2.0版本的安裝包,可以直接下載:
seata-server-1.2.0.zip
鏈接:https://pan.baidu.com/s/11UudlHOorckhXgNwv1GsuA
提取碼:g38r
seata-server-1.2.0.tar.gz
鏈接:https://pan.baidu.com/s/1gh5ogjph7wP6NfCFw2Vqvw
提取碼:t4ik
Linux
系統下我們通過命令 tar -xvf
來解壓tar.gz
壓縮文件:
tar -xvf
seata-server-1.2.0.tar.gz
解壓完成后我們得到了幾個文件夾。
- bin
存放各個系統的
seata server
啟動腳本 - conf
存在
seata server
啟動時所需要的配置信息、數據庫模式下所需要的建表語句 - lib
運行
seata server
所需要的依賴包列表
2.配置Seata Server
seata server
所有的配置都在conf
文件夾內,該文件夾內有兩個文件我們必須要詳細介紹下。
seata server
默認使用file
(文件方式)進行存儲事務日志
、事務運行信息
,我們可以通過-m db
腳本參數的形式來指定,目前僅支持file
、db
這兩種方式。
- file.conf
該文件用於配置
存儲方式
、透傳事務信息的NIO
等信息,默認對應registry.conf
文件內的file
方式配置。 - registry.conf
seata server
核心配置文件,可以通過該文件配置服務注冊方式
、配置讀取方式
。注冊方式目前支持file 、nacos 、eureka、redis、zk、consul、etcd3、sofa等方式,默認為
file
,對應讀取file.co
讀取配置信息的方式支持file、nacos 、apollo、zk、consul、etcd3等方式,默認為file
,對應讀取file.conf
## transaction log store, only used in seata-server
file.conf

## transaction log store, only used in seata-server store { ## store mode: file、db mode = "file" ## file store property file { ## store location dir dir = "sessionStore" # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions maxBranchSessionSize = 16384 # globe session size , if exceeded throws exceptions maxGlobalSessionSize = 512 # file buffer size , if exceeded allocate new buffer fileWriteBufferCacheSize = 16384 # when recover batch read size sessionReloadReadSize = 100 # async, sync flushDiskMode = async } ## database store property db { ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc. datasource = "druid" ## mysql/oracle/postgresql/h2/oceanbase etc. dbType = "mysql" driverClassName = "com.mysql.jdbc.Driver" url = "jdbc:mysql://127.0.0.1:3306/seata" user = "mysql" password = "mysql" minConn = 5 maxConn = 30 globalTable = "global_table" branchTable = "branch_table" lockTable = "lock_table" queryLimit = 100 maxWait = 5000 } }
registry.conf

registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "file" nacos { application = "seata-server" serverAddr = "localhost" namespace = "" cluster = "default" username = "" password = "" } eureka { serviceUrl = "http://localhost:8761/eureka" application = "default" weight = "1" } redis { serverAddr = "localhost:6379" db = 0 password = "" cluster = "default" timeout = 0 } zk { cluster = "default" serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } consul { cluster = "default" serverAddr = "127.0.0.1:8500" } etcd3 { cluster = "default" serverAddr = "http://localhost:2379" } sofa { serverAddr = "127.0.0.1:9603" application = "default" region = "DEFAULT_ZONE" datacenter = "DefaultDataCenter" cluster = "default" group = "SEATA_GROUP" addressWaitTime = "3000" } file { name = "file.conf" } } config { # file、nacos 、apollo、zk、consul、etcd3 type = "file" nacos { serverAddr = "localhost" namespace = "" group = "SEATA_GROUP" username = "" password = "" } consul { serverAddr = "127.0.0.1:8500" } apollo { appId = "seata-server" apolloMeta = "http://192.168.1.204:8801" namespace = "application" } zk { serverAddr = "127.0.0.1:2181" sessionTimeout = 6000 connectTimeout = 2000 username = "" password = "" } etcd3 { serverAddr = "http://localhost:2379" } file { name = "file.conf" } }
根據自己的環境進行配置:
registry.conf 我選擇eureka做注冊中心,其他不變如下圖
file.conf 配置存儲類型db,配置數據庫,如下圖
3.啟動Seata Server
啟動seata server
的腳本位於bin
文件內,Linux/Mac
環境使用seata-server.sh腳本啟動,Windows
環境使用seata-server.bat腳本啟動。
Linux/Mac
啟動方式示例如下所示:
nohup sh seata-server.sh -p 8091 -h 127.0.0.1 -m file &> seata.log &
通過nohup
命令讓seata server
在系統后台運行。
腳本參數:
- -p
指定啟動
seata server
的端口號。 - -h
指定
seata server
所綁定的主機
,這里配置要注意指定的主機IP要與業務服務內的配置文件保持一致,如:-h 192.168.1.10
,業務服務配置文件內應該配置192.168.1.10
,即使在同一台主機上也要保持一致。 - -m
事務日志、事務執行信息存儲的方式,目前支持
file
(文件方式)、db
(數據庫方式,建表語句請查看config/db_store.sql
、config/db_undo_log.sql
)
事務日志、事務執行信息存儲的方式選擇db 需要創建數據庫seata sql如下

-- the table to store GlobalSession data drop table if exists `global_table`; create table `global_table` ( `xid` varchar(128) not null, `transaction_id` bigint, `status` tinyint not null, `application_id` varchar(32), `transaction_service_group` varchar(32), `transaction_name` varchar(128), `timeout` int, `begin_time` bigint, `application_data` varchar(2000), `gmt_create` datetime, `gmt_modified` datetime, primary key (`xid`), key `idx_gmt_modified_status` (`gmt_modified`, `status`), key `idx_transaction_id` (`transaction_id`) ); -- the table to store BranchSession data drop table if exists `branch_table`; create table `branch_table` ( `branch_id` bigint not null, `xid` varchar(128) not null, `transaction_id` bigint , `resource_group_id` varchar(32), `resource_id` varchar(256) , `lock_key` varchar(128) , `branch_type` varchar(8) , `status` tinyint, `client_id` varchar(64), `application_data` varchar(2000), `gmt_create` datetime, `gmt_modified` datetime, primary key (`branch_id`), key `idx_xid` (`xid`) ); -- the table to store lock data drop table if exists `lock_table`; create table `lock_table` ( `row_key` varchar(128) not null, `xid` varchar(96), `transaction_id` long , `branch_id` long, `resource_id` varchar(256) , `table_name` varchar(32) , `pk` varchar(36) , `gmt_create` datetime , `gmt_modified` datetime, primary key(`row_key`) );
二、項目集成
經典案例可以從GitHub上下載開源demo https://github.com/seata/seata-samples
為了方便這里將案例工程springcloud-eureka-feign-mybatis-seata放在百度雲盤上,可以直接提取
鏈接:https://pan.baidu.com/s/1bumMZV8Fd4dpQoFrd4CwiQ
提取碼:dy7l
依賴的seata maven包(無法將file.conf和registry.conf兩個配置文件中的配置寫到 .properties配置文件中)
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-seata</artifactId> <version>2.1.0.RELEASE</version> <exclusions> <exclusion> <artifactId>seata-all</artifactId> <groupId>io.seata</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>${seata.version}</version> </dependency>
為了方便配置(將file.conf和registry.conf兩個配置文件中的配置寫到 .properties配置文件中)需要依賴:
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-seata</artifactId> <version>2.2.0.RELEASE</version> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.2.0</version>
</dependency>
配置文件: application.properties
seata.enabled=true seata.application-id=user-svr seata.tx-service-group=fsp_tx_user_svr_group # seata.client # 事務群組(可以每個應用獨立取名,也可以使用相同的名字) seata.client.rm.report-success-enable=true # 自動刷新緩存中的表結構(默認false) seata.client.rm.table-meta-check-enable=false # 一階段結果上報TC重試次數(默認5) seata.client.rm.report-retry-count=5 # 異步提交緩存隊列長度(默認10000) seata.client.rm.async-commit-buffer-limit=10000 # 校驗或占用全局鎖重試間隔(默認10ms) seata.client.rm.lock.retry-interval=10 # 校驗或占用全局鎖重試次數(默認30) seata.client.rm.lock.retry-times=30 # 分支事務與其它全局回滾事務沖突時鎖策略(優先釋放本地鎖讓回滾成功) seata.client.rm.lock.retry-policy-branch-rollback-on-conflict=true # 一階段全局提交結果上報TC重試次數(默認1次,建議大於1) seata.client.tm.commit-retry-count=3 # 一階段全局回滾結果上報TC重試次數(默認1次,建議大於1) seata.client.tm.rollback-retry-count=3 # 二階段回滾鏡像校驗(默認true開啟) seata.client.undo.data-validation=true # undo序列化方式(默認jackson) seata.client.undo.log-serialization=jackson # 自定義undo表名(默認undo_log) seata.client.undo.log-table=undo_log # 日志異常輸出概率(默認100) seata.client.log.exceptionRate=100 # seata.service # TC 集群(必須與seata-server保持一致) seata.service.vgroup-mapping.fsp_tx_user_svr_group=default # 降級開關 seata.service.enable-degrade=false # 禁用全局事務(默認false) seata.service.disable-global-transaction=false seata.service.grouplist.default=192.168.1.33:8091 # seata.transport seata.transport.type=TCP seata.transport.server=NIO seata.transport.heartbeat=true seata.transport.serialization=seata seata.transport.compressor=none seata.transport.shutdown.wait=3 seata.transport.thread-factory.boss-thread-prefix=NettyBoss seata.transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker seata.transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler seata.transport.thread-factory.share-boss-worker=false seata.transport.thread-factory.client-selector-thread-prefix=NettyClientSelector seata.transport.thread-factory.client-selector-thread-size=1 seata.transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread # 客戶端事務消息請求是否批量合並發送(默認true) seata.transport.enable-client-batch-send-request=true #seata.registry seata.registry.type=file seata.config.type=file seata.config.file.name=file.conf
在業務相關的數據庫中添加 undo_log 表,用於保存需要回滾的數據
CREATE TABLE `undo_log` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT, `branch_id` BIGINT(20) NOT NULL, `xid` VARCHAR(100) NOT NULL, `context` VARCHAR(128) NOT NULL, `rollback_info` LONGBLOB NOT NULL, `log_status` INT(11) NOT NULL, `log_created` DATETIME NOT NULL, `log_modified` DATETIME NOT NULL, `ext` VARCHAR(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`) ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8
四個服務:注冊中心:eureka-server ;訂單服務:order-server ;倉庫服務:storage-server ;賬戶服務:account-server ;演示的業務是增加一個訂單,賬戶減金額,倉庫減庫存,生成訂單
為了調同通這個demo廢了老大勁了
1)修改配置文件application.yml以倉庫服務為例:為了方面,這里我創建了一個數據庫inst1,三個工程都有sql文件,在數據庫中建表,切記還要創建undo_log 表
2)修改registry.conf文件,主要修改使用注冊中心的類型為:Eureka,如下
3)修改file.conf 如下
注:這里需要重點說一個坑,倉庫中下載下來的工程中vgroupMapping的配置存在問題,找了很久一直報錯
no available service 'null' found, please make sure registry config correct
忽視掉的一個配置yml中的 spring.cloud.alibaba.seata.tx-service-group= fsp_tx_storage_server_group 必須要和 file.conf 中 vgroupMapping 的 key 值為 fsp_tx_storage_server_group :
spring: application: name: storage-server cloud: alibaba: seata: tx-service-group: fsp_tx_storage_server_group
否則就會報錯!!!!
三、測試調試
為了方便驗證結果,可以在訂單服務中做如下修改操作,然后啟動所有工程進行調試,看數據庫中的數據變化,以及異常是否回滾
四、幾個坑點
1、代理數據源的配置
import com.alibaba.druid.pool.DruidDataSource; import io.seata.rm.datasource.DataSourceProxy; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.transaction.SpringManagedTransactionFactory; import org.springframework.boot.context.properties.ConfigurationProperties; 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; /** * Created by IntelliJ IDEA * 這是一個神奇的Class * * @author zhz * @date 2020/5/21 20:41 */ @Configuration public class DataSourceProxyConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); return druidDataSource; } @Primary @Bean("dataSource") public DataSourceProxy dataSource(DataSource druidDataSource){ return new DataSourceProxy(druidDataSource); } @Bean public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSourceProxy); sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("classpath*:/mapper/*.xml")); sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory()); return sqlSessionFactoryBean.getObject(); } }
2、啟動類配置
SpringBootApplication注解需要添加 DataSourceAutoConfiguration 讓代理數據源起效
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
3、SpringBoot和springCloud的版本問題引起的
Spring Cloud Spring Boot
Angel版本 兼容Spring Boot 1.2.x
Brixton版本 兼容Spring Boot 1.3.x,也兼容Spring Boot 1.4.x
Camden版本 兼容Spring Boot 1.4.x,也兼容Spring Boot 1.5.x
Dalston版本、Edgware版本 兼容Spring Boot 1.5.x,不兼容Spring Boot 2.0.x
Finchley版本 兼容Spring Boot 2.0.x,不兼容Spring Boot 1.5.x
Greenwich版本 兼容Spring Boot 2.1.x
SpringCloud的Finchley、Greenwich兩個版本的@FeignClient 的屬性value(name)略有不同,Finchley可以保持多個同名的feign,而Greenwich必須只有一個
4、在實際配置中,項目是SpringBoot+SpringCloud+Feign+Redis+Shiro+Seata,會產生目前不明的bug,博主推測是是Shiro和Seata的兼容問題,導致事務的分支事務無法回滾;
5、數據庫表存在多主鍵的表,暫時不支持
https://www.cnblogs.com/victorbu/p/12738556.html
這只是一個簡單的springCloud-eureka-feign-mybatis-seata的demo測試,如何集成到自己的項目中還是要自己摸索清楚,至少調通了這個demo就邁出了一大步