## :-: springcloud 整合Seata實現分布式事務
## Seata簡介 [https://github.com/seata](https://github.com/seata)
Seata(Simple Extensible Autonomous Transaction Architecture) 是 阿里巴巴開源的分布式事務中間件,以高效并且對業務 0 侵入的方式,解決微服務場景下面臨的分布式事務問題。
## Seata解決方案
先介紹 `Seata` 分布式事務的幾種角色:
* `Transaction Coordinator(TC)`: ?全局事務協調者,用來協調全局事務和各個分支事務(不同服務)的狀態, 驅動全局事務和各個分支事務的回滾或提交。
* `Transaction Manager?`: ?事務管理者,業務層中用來開啟/提交/回滾一個整體事務(在調用服務的方法中用注解開啟事務)。
* `Resource Manager(RM)`: ?資源管理者,一般指業務數據庫代表了一個分支事務(`Branch Transaction`),管理分支事務與 `TC` 進行協調注冊分支事務并且匯報分支事務的狀態,驅動分支事務的提交或回滾。
典型的分布式事務周期包括以下步驟:
* TM向TC請求開啟一個全局事務,TC給TM返回一個全局事務的XID;
* XID在微服務調用鏈之間傳遞;
* RM向TC注冊XID下的分支事務;
* TM根據XID向TC發出提交或者回滾的請求;
* TC根據XID使RM提交或者回滾。
Seata 也是從兩段提交演變而來的一種分布式事務解決方案,提供了 AT、TCC、SAGA 和 XA 等事務模式,這里重點介紹 AT模式。
#### AT模式
1、基于支持本地 ACID 事務的關系型數據庫,整體機制是2PC的演變。
~~~
一階段:業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。
二階段:提交異步化,成功則批量地刪除相應回滾日志記錄,回滾則通過回滾日志進行反向補償。
~~~
2、寫隔離。
~~~
1)一階段本地事務提交前,需要確保先拿到全局鎖。
2)拿不到全局鎖,不能提交本地事務;拿到全局鎖,提交本地事務并插入undo_log記錄。
3)拿全局鎖的嘗試被限制在一定范圍內,超出范圍將放棄,并根據undo_log記錄回滾本地事務,釋放本地鎖。
~~~
3、讀隔離。
~~~
1)在數據庫本地事務隔離級別 讀已提交(Read Committed) 或以上的基礎上,Seata(AT 模式)
的默認全局隔離級別是 讀未提交(Read Uncommitted)。
理解:在全局事務提交之前,本地事務會先提交,這時候查詢數據,對于本地庫是Read Committed,
對于全局來說是 Read Uncommitted。
2)如果要求全局的讀已提交,目前 Seata 的方式是通過 SELECT FOR UPDATE 語句的代理。
~~~
## **springcloud 整合Seata實現分布式事務**
項目使用的是SpringBoot 2.x + SpringCloud,注冊中心使用的是nacos
### **一、seata-server搭建**
1、下載最新版seata-server-1.4.0.zip
2、修改registry.conf。
registry.type 改成nacos 然后配置nacos 如下
```
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
loadBalance = "RandomLoadBalance"
loadBalanceVirtualNodes = 10
nacos {
application = "seata-server"
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
namespace = ""
cluster = "default"
username = ""
password = ""
}
```
3、使用file.conf,store.mode選擇db,修改連接的數據庫屬性,其他的默認即可。
```
db {
datasource = "druid"
## mysql/oracle/postgresql/h2/oceanbase etc.
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://*************.mysql.rds.aliyuncs.com:3306/hj_seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&zeroDateTimeBehavior=convertToNull&useSSL=false"
user = "root"
password = "****"
minConn = 5
maxConn = 100
globalTable = "global_table"
branchTable = "branch_table"
lockTable = "lock_table"
queryLimit = 100
maxWait = 5000
}
```
4、在數據庫中加入三個表。
```
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table` (
`branch_id` bigint(20) NOT NULL,
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`resource_group_id` varchar(32) DEFAULT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`lock_key` varchar(128) DEFAULT NULL,
`branch_type` varchar(8) DEFAULT NULL,
`status` tinyint(4) DEFAULT NULL,
`client_id` varchar(64) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `global_table` (
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`application_id` varchar(64) DEFAULT NULL,
`transaction_service_group` varchar(64) DEFAULT NULL,
`transaction_name` varchar(64) DEFAULT NULL,
`timeout` int(11) DEFAULT NULL,
`begin_time` bigint(20) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `lock_table` (
`row_key` varchar(128) NOT NULL,
`xid` varchar(96) DEFAULT NULL,
`transaction_id` mediumtext,
`branch_id` mediumtext,
`resource_id` varchar(256) DEFAULT NULL,
`table_name` varchar(32) DEFAULT NULL,
`pk` varchar(32) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`row_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
5、在bin目錄下,啟動server服務,默認是8091端口。
### **二、springCloud 項目整合**
**Springboot:2.3.2.RELEASE**
**springCloud alibaba:2.2.0.RELEASE**
**springCloud :Hoxton.RELEASE**
**搭建2個微服務項目hj-seata-client1 hj-seata-client2 調用關系為 hj-seata-client調用hj-seata-client1的服務**
**1、配置**
~~~
<dependencies>
<dependency>
<groupId>com.hjf.mall</groupId>
<artifactId>hj-common</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>
<!--mysql: 數據庫鏈接驅動工具 8.0版本可以對應數據庫5.6、5.7、8.0 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--java工具類 Bean注解簡化開發-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- mybatis-plus start -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<artifactId>seata-spring-boot-starter</artifactId>
<groupId>io.seata</groupId>
</exclusion>
</exclusions>
</dependency>
<!--阿里分布式事務-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.0</version>-->
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--cloud依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
~~~
**application.yml**
*****
~~~
server:
port: 6002
spring:
main:
allow-bean-definition-overriding: true
application:
name: seata-B
# --------------cloud配置------------------
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #注冊服務控制中心
# 這里配置分組
alibaba:
seata:
tx-service-group: my_test_tx_group
#------------數據庫鏈接-----------------------------
datasource:
url: jdbc:mysql://****.mysql.rds.aliyuncs.com:3306/hj_mall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: ***
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
mapper-locations: classpath:/mapper/*Mapper.xml
#實體掃描,多個package用逗號或者分號分隔
typeAliasesPackage: com.hjf.test.entity,com.hjf.base,MyOgnl
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 是否開啟自動駝峰命名規則(camel case)映射,即從經典數據庫列名 A_COLUMN(下劃線命名) 到經典 Java 屬性名 aColumn(駝峰命名) 的類似映射
map-underscore-to-camel-case: false
global-config:
db-config:
id-type: auto
#開啟hystrix 熔斷
feign:
hystrix:
enabled: true
client:
config:
default:
connect-timeout: 4000
read-timeout: 4000
# --------------負載均衡器配置------------------
ribbon:
ReadTimeout: 60000
ConnectTimeout: 60000
#阿里分布式事務配置
seata:
service:
tx-service-group: my_test_tx_group
vgroup-mapping:
#這里的組名my_test_tx_group就是上面已經配置過的
# seata-server 對應的就是register.conf里的application選項的內容
my_test_tx_group: seata-server
grouplist:
#這里對應的就是上面的seata-server,后面的蠶食seata服務的IP地址和端口號
seata-server: 127.0.0.1:8091
enable-degrade: false
disable-global-transaction: false
~~~
*****
**2、配置數據源代理和掃描器**
~~~
@Configuration
public class DataSourceProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
~~~
**3、在需要開啟分布式事務的方法上加上@GlobalTransactional注解。**
~~~
在TM開啟全局事務之后,TC返回一個XID,RootContext類中會保存XID,該XID是一個線程變量。
RM中根據XID向TC注冊分支變量。
~~~
*****
~~~
@GlobalTransactional(rollbackFor = Exception.class)
public BaseResp addCarousel(MarketCarousel q) {
marketCarouselMapper.insert(q);
//遠程調用微服務添加數據
BaseResp r=feignService.add(q);
if (StringUtils.isBlank(q.getTitle())){
//拋出異常事務回滾
throw new NullPointerException("拋出異常........");
}
return BaseResp.SUCCESS;
}
~~~
*****
**4、在業務系統和各個微服務中加入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;
~~~
- 項目介紹
- 項目聲明
- 項目簡介
- 架構設計
- 項目亮點功能介紹
- 技術棧介紹
- 核心功能
- 運行環境
- 項目更新日志
- 文檔更新日志
- F&Q
- 部署教程
- 環境準備
- JDK安裝
- JDK1.8,17共存
- maven
- 分布式緩存Redis
- 單機版
- 集群
- 注冊&配置中心alibaba/nacos
- 介紹
- Nacos安裝
- Nacos配置中心
- Nacos注冊發現
- Nacos生產部署方案
- 服務監控-BootAdmin
- 基本介紹
- 如何使用
- 整合Admin-Ui
- 客戶端配置
- 鏈路追蹤
- 基本介紹
- SkyWalking-1
- Skywalking-1
- 消息隊列
- Kafka
- docker安裝kafka
- Linux集群
- Maven私服
- nexus安裝部署
- nexus使用介紹
- 全文搜索elasticsearch
- windows集群搭建
- docker安裝es
- ElasticHD
- linux集群部署
- 統一日志解決方案
- 日志解決方案設計
- 介紹與相關資料
- ELK安裝部署
- elasticsearch 7.5
- logstash-7.5
- kibana-7.5
- filebeat
- 服務監控-Prometheus
- Prometheus安裝配置
- Prometheus介紹
- grafana
- 持續集成部署CICD
- 自動化部署Jenkins
- 安裝部署win
- 打包發布遠程執行
- 安裝部署linux
- jenkins+gitlab+docker容器化工程自動化部署
- Git
- CICD說明
- 阿里云效
- CentOS_MYSQL安裝
- docker
- 安裝
- Docker安裝Nginx
- Docker部署啟動springboot
- dockerCompose
- harbor
- Docker私有鏡像倉庫
- Portainer
- Docker遠程連接設置
- 打包工程
- 必要啟動模塊
- 核心模塊
- 登錄認證
- 緩存功能
- 日志模塊
- 分布式鎖
- 消息隊列
- 異常處理
- 系統接口
- 參數驗證
- es檢索
- 數據導出
- 系統設計
- 系統總體架構
- 擴展模塊(可選)
- 限流熔斷alibaba/sentinel
- 使用Sentinel實現gateway網關及服務接口限流
- Sentinel使用Nacos存儲規則及同步
- 服務調用Feign
- Feign基本介紹
- 如何使用
- 負載均衡
- 請求超時
- 請求攔截器
- 分布式任務調度
- XXL-JOB
- 分布式事務
- TX-LCN
- Seata
- Seata原理解析
- 數據庫分庫分表
- swagger文檔
- 分布式ID生成器解決方案
- 服務網關CloudGateway
- 基本介紹
- 使用網關
- 路由配置
- 全局過濾器
- 服務認證授權架構設計
- 認證服務流程
- 授權服務流程
- 系統冪等性設計與實踐
- 分布式日志鏈路跟蹤
- 實時搜索系統設計
- 應用性能
- 壓力測試工具
- Apache JMeter介紹和安裝
- ApacheJMeter使用
- JVM
- JVM性能調優
- 常見JVM內存錯誤及解決方案
- JVM 分析工具詳解
- Spring Cloud性能調優
- Linux運維
- Linux 常用命令
- Linux開啟端口