@@ -9,7 +9,7 @@ Apache ShardingSphere 提供 BASE 事务,集成了 Seata 的实现。本文所
9
9
10
10
## 前提条件
11
11
12
- ShardingSphere 的 Seata 集成仅在 ` apache/incubator-seata:v2.1 .0 ` 或更高版本可用。
12
+ ShardingSphere 的 Seata 集成仅在 ` apache/incubator-seata:v2.2 .0 ` 或更高版本可用。
13
13
对于 ` org.apache.seata:seata-all ` Maven 模块对应的 Seata Client,此限制同时作用于 HotSpot VM 和 GraalVM Native Image。
14
14
引入 Maven 依赖,并排除 ` org.apache.seata:seata-all ` 中过时的 ` org.antlr:antlr4-runtime:4.8 ` 的 Maven 依赖。
15
15
@@ -29,7 +29,7 @@ ShardingSphere 的 Seata 集成仅在 `apache/incubator-seata:v2.1.0` 或更高
29
29
<dependency >
30
30
<groupId >org.apache.seata</groupId >
31
31
<artifactId >seata-all</artifactId >
32
- <version >2.1 .0</version >
32
+ <version >2.2 .0</version >
33
33
<exclusions >
34
34
<exclusion >
35
35
<groupId >org.antlr</groupId >
@@ -42,47 +42,17 @@ ShardingSphere 的 Seata 集成仅在 `apache/incubator-seata:v2.1.0` 或更高
42
42
```
43
43
44
44
受 Calcite 的影响,ShardingSphere JDBC 使用的 ` commons-lang:commons-lang ` 和 ` org.apache.commons:commons-pool2 ` 与 Seata Client 存在依赖冲突,
45
- 需用户根据实际情景考虑是否需要解决依赖冲突。
45
+ 需用户根据实际情景考虑是否需要解决依赖冲突。如果不解决依赖冲突,Maven 等构建工具会在 classpath 随机使用一个冲突依赖的版本。
46
46
47
47
使用 ShardingSphere 的 Seata 集成模块时,ShardingSphere 连接的数据库实例应同时实现 ShardingSphere 的方言解析支持与 Seata AT 模式的方言解析支持。
48
48
这类数据库包括但不限于 ` mysql ` ,` gvenzl/oracle-free ` ,` gvenzl/oracle-xe ` ,` postgres ` ,` mcr.microsoft.com/mssql/server ` 等 Docker Image。
49
49
50
- ## 操作步骤
51
-
52
- 1 . 启动 Seata Server
53
- 2 . 创建日志表
54
- 3 . 添加 Seata 配置
55
-
56
- ## 配置示例
57
-
58
- ### 启动 Seata Server
59
-
60
- 按照如下任一链接的步骤,下载并启动 Seata 服务器。
61
- 合理的启动方式应通过 Docker Hub 中的 ` apache/seata-server ` 的 Docker Image 来实例化 Seata 服务器。
50
+ ### ` undo_log ` 表限制
62
51
63
- - https://hub.docker.com/r/apache/seata-server
52
+ 在每一个 ShardingSphere 涉及的真实数据库实例中均需要创建 ` undo_log ` 表。
53
+ 每种数据库的 SQL 的内容以 https://github.com/apache/incubator-seata/tree/v2.2.0/script/client/at/db 内对应的数据库为准。
64
54
65
- ### 创建 undo_log 表
66
-
67
- 在每一个 ShardingSphere 涉及的真实数据库实例中创建 ` undo_log ` 表。
68
- SQL 的内容以 https://github.com/apache/incubator-seata/tree/v2.1.0/script/client/at/db 内对应的数据库为准。
69
- 以下内容以 MySQL 为例。
70
- ``` sql
71
- CREATE TABLE IF NOT EXISTS ` undo_log`
72
- (
73
- ` branch_id` BIGINT NOT NULL COMMENT ' branch transaction id' ,
74
- ` xid` VARCHAR (128 ) NOT NULL COMMENT ' global transaction id' ,
75
- ` context` VARCHAR (128 ) NOT NULL COMMENT ' undo_log context,such as serialization' ,
76
- ` rollback_info` LONGBLOB NOT NULL COMMENT ' rollback info' ,
77
- ` log_status` INT (11 ) NOT NULL COMMENT ' 0:normal status,1:defense status' ,
78
- ` log_created` DATETIME(6 ) NOT NULL COMMENT ' create datetime' ,
79
- ` log_modified` DATETIME(6 ) NOT NULL COMMENT ' modify datetime' ,
80
- UNIQUE KEY ` ux_undo_log` (` xid` , ` branch_id` )
81
- ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT = ' AT transaction mode undo table' ;
82
- ALTER TABLE ` undo_log` ADD INDEX ` ix_log_created` (` log_created` );
83
- ```
84
-
85
- ### 修改配置
55
+ ### 相关配置
86
56
87
57
在自有项目的 ShardingSphere 的 YAML 配置文件写入如下内容,参考 [ 分布式事务] ( /cn/user-manual/shardingsphere-jdbc/yaml-config/rules/transaction ) 。
88
58
若初始化 ShardingSphere JDBC DataSource 时使用的是 Java API,参考 [ 分布式事务] ( /cn/user-manual/shardingsphere-jdbc/java-api/rules/transaction ) 。
@@ -93,16 +63,16 @@ transaction:
93
63
providerType : Seata
94
64
` ` `
95
65
96
- 在 classpath 的根目录中增加 ` seata.conf` 文件,
97
- 配置文件格式参考 `org.apache.seata.config.FileConfiguration` 的 [JavaDoc](https://github.com/apache/incubator-seata/blob/v2.1 .0/config/seata-config-core/src/main/java/org/apache/seata/config/FileConfiguration.java)。
66
+ 在 classpath 的根目录中增加 ` seata.conf` 文件,
67
+ 配置文件格式参考 `org.apache.seata.config.FileConfiguration` 的 [JavaDoc](https://github.com/apache/incubator-seata/blob/v2.2 .0/config/seata-config-core/src/main/java/org/apache/seata/config/FileConfiguration.java)。
98
68
99
69
` seata.conf` 存在四个属性,
100
70
101
71
1. `shardingsphere.transaction.seata.at.enable`,当此值为`true`时,开启 ShardingSphere 的 Seata AT 集成。存在默认值为 `true`
102
72
2. `shardingsphere.transaction.seata.tx.timeout`,全局事务超时(秒)。存在默认值为 `60`
103
73
3. `client.application.id`,应用唯一主键,用于设置 Seata Transaction Manager Client 和 Seata Resource Manager Client 的 `applicationId`
104
74
4. `client.transaction.service.group`,所属事务组, 用于设置 Seata Transaction Manager Client 和 Seata Resource Manager Client 的 `transactionServiceGroup`。
105
- 存在默认值为 `default`
75
+ 存在默认值为 `default`
106
76
107
77
一个完全配置的 `seata.conf` 如下,
108
78
@@ -117,7 +87,7 @@ client {
117
87
` ` `
118
88
119
89
一个最小配置的 `seata.conf` 如下。
120
- 由 ShardingSphere 管理的 `seata.conf` 中, `client.transaction.service.group` 的默认值设置为 `default` 是出于历史原因。
90
+ 由 ShardingSphere 管理的 `seata.conf` 中, `client.transaction.service.group` 的默认值为 `default` 是出于历史原因。
121
91
假设用户使用的 Seata Server 和 Seata Client 的 `registry.conf` 中,`registry.type` 和 `config.type` 均为 `file`,
122
92
则对于 `registry.conf` 的 `config.file.name` 配置的 `.conf` 文件中,事务分组名在 `apache/incubator-seata:v1.5.1` 及之后默认值为 `default_tx_group`,
123
93
在 `apache/incubator-seata:v1.5.1` 之前则为 `my_test_tx_group`。
@@ -128,6 +98,200 @@ client.application.id = example
128
98
129
99
根据实际场景修改 Seata 的 `registry.conf` 文件。
130
100
101
+ # # 操作步骤
102
+
103
+ 1. 启动 Seata Server
104
+ 2. 创建 `undo_log` 表
105
+ 3. 添加 Seata 配置
106
+
107
+ # # 配置示例
108
+
109
+ # ## 启动 Seata Server 和 MySQL Server
110
+
111
+ 编写 Docker Compose 文件来启动 Seata Server 和 MySQL Server。
112
+
113
+ ` ` ` yaml
114
+ services:
115
+ apache-seata-server:
116
+ image: apache/seata-server:2.2.0
117
+ ports:
118
+ - "8091:8091"
119
+ mysql:
120
+ image: mysql:9.1.0
121
+ environment:
122
+ MYSQL_ROOT_PASSWORD: example
123
+ volumes:
124
+ - ./mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
125
+ ports:
126
+ - "3306:3306"
127
+ ` ` `
128
+
129
+ ` ./docker-entrypoint-initdb.d` 文件夹包含文件为 `init.sh`,内容如下,
130
+
131
+ ` ` ` shell
132
+ #!/bin/bash
133
+ set -e
134
+
135
+ mysql -uroot -p"$MYSQL_ROOT_PASSWORD" <<EOSQL
136
+ CREATE DATABASE demo_ds_0;
137
+ CREATE DATABASE demo_ds_1;
138
+ CREATE DATABASE demo_ds_2;
139
+ EOSQL
140
+
141
+ for i in "demo_ds_0" "demo_ds_1" "demo_ds_2"
142
+ do
143
+ mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$i" <<'EOSQL'
144
+ CREATE TABLE IF NOT EXISTS ` undo_log`
145
+ (
146
+ ` branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
147
+ ` xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
148
+ ` context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
149
+ ` rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
150
+ ` log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
151
+ ` log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
152
+ ` log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
153
+ UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
154
+ ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table';
155
+ ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`);
156
+
157
+ CREATE TABLE IF NOT EXISTS t_order (
158
+ order_id BIGINT NOT NULL AUTO_INCREMENT,
159
+ order_type INT(11),
160
+ user_id INT NOT NULL,
161
+ address_id BIGINT NOT NULL,
162
+ status VARCHAR(50),
163
+ PRIMARY KEY (order_id)
164
+ );
165
+ EOSQL
166
+ done
167
+ ```
168
+
169
+ ### 在业务项目的 classpath 创建 ` seata.conf `
170
+
171
+ 在业务项目的 classpath 创建 ` seata.conf ` ,内容如下,
172
+
173
+ ```
174
+ service {
175
+ default.grouplist = "127.0.0.1:8091"
176
+ vgroupMapping.default_tx_group = "default"
177
+ }
178
+ ```
179
+
180
+ ### 在业务项目的 classpath 创建 ` file.conf `
181
+
182
+ 在业务项目的 classpath 创建 ` file.conf ` ,内容如下,
183
+
184
+ ```
185
+ client {
186
+ application.id = test
187
+ transaction.service.group = default_tx_group
188
+ }
189
+ ```
190
+
191
+ ### 在业务项目的 classpath 创建 ` registry.conf `
192
+
193
+ 在业务项目的 classpath 创建 ` registry.conf ` ,内容如下,
194
+
195
+ ```
196
+ registry {
197
+ type = "file"
198
+ file {
199
+ name = "file.conf"
200
+ }
201
+ }
202
+ config {
203
+ type = "file"
204
+ file {
205
+ name = "file.conf"
206
+ }
207
+ }
208
+ ```
209
+
210
+ ### 在业务项目创建 ShardingSphere 配置文件
211
+
212
+ 在业务项目引入前提条件涉及的依赖后,在业务项目的 classpath 上编写 ShardingSphere 数据源的配置文件` demo.yaml ` ,
213
+
214
+ ``` yaml
215
+ dataSources :
216
+ ds_0 :
217
+ dataSourceClassName : com.zaxxer.hikari.HikariDataSource
218
+ driverClassName : com.mysql.cj.jdbc.Driver
219
+ jdbcUrl : jdbc:mysql://localhost:3306/demo_ds_0?sslMode=REQUIRED
220
+ username : root
221
+ password : example
222
+ ds_1 :
223
+ dataSourceClassName : com.zaxxer.hikari.HikariDataSource
224
+ driverClassName : com.mysql.cj.jdbc.Driver
225
+ jdbcUrl : jdbc:mysql://localhost:3306/demo_ds_1?sslMode=REQUIRED
226
+ username : root
227
+ password : example
228
+ ds_2 :
229
+ dataSourceClassName : com.zaxxer.hikari.HikariDataSource
230
+ driverClassName : com.mysql.cj.jdbc.Driver
231
+ jdbcUrl : jdbc:mysql://localhost:3306/demo_ds_2?sslMode=REQUIRED
232
+ username : root
233
+ password : example
234
+ rules :
235
+ - !SHARDING
236
+ tables :
237
+ t_order :
238
+ actualDataNodes : ds_$->{0..2}.t_order
239
+ keyGenerateStrategy :
240
+ column : order_id
241
+ keyGeneratorName : snowflake
242
+ defaultDatabaseStrategy :
243
+ standard :
244
+ shardingColumn : user_id
245
+ shardingAlgorithmName : inline
246
+ shardingAlgorithms :
247
+ inline :
248
+ type : INLINE
249
+ props :
250
+ algorithm-expression : ds_${user_id % 2}
251
+ keyGenerators :
252
+ snowflake :
253
+ type : SNOWFLAKE
254
+ transaction :
255
+ defaultType : BASE
256
+ providerType : Seata
257
+ ` ` `
258
+
259
+ ### 享受集成
260
+
261
+ 在 ShardingSphere 的数据源上可开始享受集成,
262
+
263
+ ` ` ` java
264
+ import com.zaxxer.hikari.HikariConfig;
265
+ import com.zaxxer.hikari.HikariDataSource;
266
+ import java.sql.Connection;
267
+ import java.sql.SQLException;
268
+ @SuppressWarnings({"SqlNoDataSourceInspection", "AssertWithSideEffects"})
269
+ public class ExampleTest {
270
+ void test() throws SQLException {
271
+ HikariConfig config = new HikariConfig();
272
+ config.setJdbcUrl("jdbc:shardingsphere:classpath:demo.yaml");
273
+ config.setDriverClassName("org.apache.shardingsphere.driver.ShardingSphereDriver");
274
+ try (HikariDataSource dataSource = new HikariDataSource(config)) {
275
+ try (Connection conn = dataSource.getConnection()) {
276
+ try {
277
+ conn.setAutoCommit(false);
278
+ conn.createStatement().executeUpdate("INSERT INTO t_order (user_id, order_type, address_id, status) VALUES (2024, 1, 2024, 'INSERT_TEST')");
279
+ conn.createStatement().executeUpdate("INSERT INTO t_order_does_not_exist (test_id_does_not_exist) VALUES (2024)");
280
+ conn.commit();
281
+ } catch (final SQLException ignored) {
282
+ conn.rollback();
283
+ } finally {
284
+ conn.setAutoCommit(true);
285
+ }
286
+ }
287
+ try (Connection conn = dataSource.getConnection()) {
288
+ assert !conn.createStatement().executeQuery("SELECT * FROM t_order_item WHERE user_id = 2024").next();
289
+ }
290
+ }
291
+ }
292
+ }
293
+ ```
294
+
131
295
## 使用限制
132
296
133
297
ShardingSphere 的 Seata 集成不支持隔离级别。
@@ -137,7 +301,7 @@ ShardingSphere 的 Seata 集成将获取到的 Seata 全局事务置入线程的
137
301
这意味着用户在使用 ShardingSphere 的 Seata 集成时,用户应避免使用 ` org.apache.seata:seata-all ` 的 Java API,
138
302
除非用户正在混合使用 ShardingSphere 的 Seata 集成与 Seata Client 的 TCC 模式特性。
139
303
140
- 针对 ShardingSphere 数据源,讨论 6 种情况,
304
+ 针对 ShardingSphere 数据源,讨论 7 种情况,
141
305
142
306
1 . 手动获取从 ShardingSphere 数据源创建的 ` java.sql.Connection ` 实例,并手动调用 ` setAutoCommit() ` , ` commit() ` 和 ` rollback() ` 方法,
143
307
这是被允许的。
@@ -148,9 +312,13 @@ ShardingSphere 的 Seata 集成将获取到的 Seata 全局事务置入线程的
148
312
149
313
4 . 在函数上使用 Spring Framework 的 ` org.springframework.transaction.annotation.Transactional ` 注解,这是被允许的。
150
314
151
- 5. 在函数上使用 `org.apache.seata.spring.annotation.GlobalTransactional` 注解,这是**不被允许的**。
315
+ 5 . 手动获取从 ` org.springframework.transaction.PlatformTransactionManager ` 实例创建的 ` org.springframework.transaction.support.TransactionTemplate ` 实例,
316
+ 并使用 ` org.springframework.transaction.support.TransactionTemplate#execute(org.springframework.transaction.support.TransactionCallback) ` ,
317
+ 这是被允许的。
318
+
319
+ 6 . 在函数上使用 ` org.apache.seata.spring.annotation.GlobalTransactional ` 注解,这是** 不被允许的** 。
152
320
153
- 6 . 手动从 `org.apache.seata.tm.api.GlobalTransactionContext ` 创建 `org.apache.seata.tm.api.GlobalTransaction` 实例,
321
+ 7 . 手动从 ` org.apache.seata.tm.api.GlobalTransactionContext ` 创建 ` org.apache.seata.tm.api.GlobalTransaction ` 实例,
154
322
调用 ` org.apache.seata.tm.api.GlobalTransaction ` 实例的 ` begin() ` , ` commit() ` 和 ` rollback() ` 方法,这是** 不被允许的** 。
155
323
156
324
在使用 Spring Boot 的实际情景中,
@@ -173,7 +341,7 @@ ShardingSphere 的 Seata 集成将获取到的 Seata 全局事务置入线程的
173
341
<dependency >
174
342
<groupId >org.apache.seata</groupId >
175
343
<artifactId >seata-spring-boot-starter</artifactId >
176
- <version>2.1 .0</version>
344
+ <version >2.2 .0</version >
177
345
<exclusions >
178
346
<exclusion >
179
347
<groupId >org.antlr</groupId >
@@ -378,7 +546,7 @@ public class CustomWebMvcConfigurer implements WebMvcConfigurer {
378
546
379
547
3 . 微服务实例 ` a-service ` 和 ` b-service ` 均为 Spring Boot 微服务,但使用的 API 网关中间件阻断了所有包含 ` TX_XID ` 的 HTTP Header 的 HTTP 请求。
380
548
用户需要考虑更改把 XID 通过服务调用传递到微服务实例 ` a-service ` 使用的 HTTP Header,或使用 RPC 框架把 XID 通过服务调用传递到微服务实例 ` a-service ` 。
381
- 参考 https://github.com/apache/incubator-seata/tree/v2.1 .0/integration 。
549
+ 参考 https://github.com/apache/incubator-seata/tree/v2.2 .0/integration 。
382
550
383
551
4 . 微服务实例 ` a-service ` 和 ` b-service ` 均为 Quarkus,Micronaut Framework 和 Helidon 等微服务。
384
552
此情况下无法使用 Spring WebMVC HandlerInterceptor。
0 commit comments