You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2026/08/31 11:15:01 UTC

(shardingsphere) branch master updated: Refine Seata transaction documentation (#39668)

This is an automated email from the ASF dual-hosted git repository.

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 1caff918380 Refine Seata transaction documentation (#39668)
1caff918380 is described below

commit 1caff918380ab73f2cf94159cd1d1716398cf370
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Mon Aug 31 19:14:54 2026 +0800

    Refine Seata transaction documentation (#39668)
---
 .../special-api/transaction/seata.cn.md            | 294 +++----------------
 .../special-api/transaction/seata.en.md            | 312 +++------------------
 2 files changed, 65 insertions(+), 541 deletions(-)

diff --git a/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.cn.md b/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.cn.md
index f048dc0b21f..9fd1a4dae2e 100644
--- a/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.cn.md
+++ b/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.cn.md
@@ -9,8 +9,8 @@ Apache ShardingSphere 提供 BASE 事务,集成了 Seata 的实现。本文所
 
 ## 前提条件
 
-ShardingSphere 的 Seata 集成仅在 `apache/incubator-seata:v2.6.0` 或更高版本可用。
-对于 `org.apache.seata:seata-all` Maven 模块对应的 Seata Client,此限制同时作用于 HotSpot VM 和 GraalVM Native Image。
+本文以 Apache Seata 2.6.0 为目标版本。
+HotSpot VM 和 GraalVM Native Image 均使用 `org.apache.seata:seata-all:2.6.0` 作为 Seata Client 依赖。
 引入 Maven 依赖,并排除 `org.apache.seata:seata-all` 中过时的 `org.antlr:antlr4-runtime:4.8` 的 Maven 依赖。
 
 ```xml
@@ -36,8 +36,7 @@ ShardingSphere 的 Seata 集成仅在 `apache/incubator-seata:v2.6.0` 或更高
 </project>
 ```
 
-使用 ShardingSphere 的 Seata 集成模块时,ShardingSphere 连接的数据库实例应同时实现 ShardingSphere 的方言解析支持与 Seata AT 模式的方言解析支持。
-这类数据库包括但不限于 `mysql`,`gvenzl/oracle-free`,`gvenzl/oracle-xe`,`postgres`,`mcr.microsoft.com/mssql/server` 等 Docker Image。
+数据库必须同时受到 ShardingSphere 和 Seata AT 模式支持。
 
 ### `undo_log` 表限制
 
@@ -291,27 +290,31 @@ transaction:
    providerType: Seata
 ```
 
-### 享受集成
+### 验证事务回滚
 
-在 ShardingSphere 的数据源上可开始享受集成,
+以下示例验证执行失败的事务会在 ShardingSphere 数据源上回滚。
 
 ```java
-import com.zaxxer.hikari.HikariConfig;
-import com.zaxxer.hikari.HikariDataSource;
 import java.sql.Connection;
+import java.sql.ResultSet;
 import java.sql.SQLException;
-@SuppressWarnings({"SqlNoDataSourceInspection", "AssertWithSideEffects"})
+import java.sql.Statement;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+@SuppressWarnings("SqlNoDataSourceInspection")
 public class ExampleTest {
     void test() throws SQLException {
         HikariConfig config = new HikariConfig();
         config.setJdbcUrl("jdbc:shardingsphere:classpath:demo.yaml");
         config.setDriverClassName("org.apache.shardingsphere.driver.ShardingSphereDriver");
         try (HikariDataSource dataSource = new HikariDataSource(config)) {
-            try (Connection conn = dataSource.getConnection()) {
+            try (Connection conn = dataSource.getConnection(); Statement statement = conn.createStatement()) {
+                conn.setAutoCommit(false);
+                statement.executeUpdate("INSERT INTO t_order (user_id, order_type, address_id, status) VALUES (2024, 1, 2024, 'INSERT_TEST')");
                 try {
-                    conn.setAutoCommit(false);
-                    conn.createStatement().executeUpdate("INSERT INTO t_order (user_id, order_type, address_id, status) VALUES (2024, 1, 2024, 'INSERT_TEST')");
-                    conn.createStatement().executeUpdate("INSERT INTO t_order_does_not_exist (test_id_does_not_exist) VALUES (2024)");
+                    statement.executeUpdate("INSERT INTO t_order_does_not_exist (test_id_does_not_exist) VALUES (2024)");
                     conn.commit();
                 } catch (final SQLException ignored) {
                     conn.rollback();
@@ -319,8 +322,11 @@ public class ExampleTest {
                     conn.setAutoCommit(true);
                 }
             }
-            try (Connection conn = dataSource.getConnection()) {
-                assert !conn.createStatement().executeQuery("SELECT * FROM t_order_item WHERE user_id = 2024").next();
+            try (Connection conn = dataSource.getConnection(); Statement statement = conn.createStatement();
+                    ResultSet resultSet = statement.executeQuery("SELECT * FROM t_order WHERE user_id = 2024")) {
+                if (resultSet.next()) {
+                    throw new IllegalStateException("Transaction rollback failed.");
+                }
             }
         }
     }
@@ -331,12 +337,10 @@ public class ExampleTest {
 
 ShardingSphere 的 Seata 集成不支持隔离级别。
 
-ShardingSphere 的 Seata 集成将获取到的 Seata 全局事务置入线程的局部变量。
-而 `org.apache.seata.spring.annotation.GlobalTransactionScanner` 则是采用 Dynamic Proxy 的方式对方法进行增强。
-这意味着用户在使用 ShardingSphere 的 Seata 集成时,用户应避免使用 `org.apache.seata:seata-all` 的 Java API,
-除非用户正在混合使用 ShardingSphere 的 Seata 集成与 Seata Client 的 TCC 模式特性。
+ShardingSphere 负责管理其 JDBC 数据源对应的 Seata 全局事务。
+不要使用其他全局事务入口管理同一个数据源上的事务。
 
-针对 ShardingSphere 数据源,讨论 7 种情况,
+以下规则适用于 ShardingSphere 数据源。
 
 1. 手动获取从 ShardingSphere 数据源创建的 `java.sql.Connection` 实例,并手动调用 `setAutoCommit()`, `commit()` 和 `rollback()` 方法,
 这是被允许的。
@@ -397,252 +401,18 @@ seata:
   enable-auto-data-source-proxy: false
 ```
 
-### 与 Seata TCC 模式特性混合使用
+### 与其他 Seata 事务模式混用
 
-对于设置开启 ShardingSphere 的 Seata 集成的情况下,
-在与 ShardingSphere JDBC DataSource 无关的业务函数中,如需在业务函数使用 Seata Client 的 Seata TCC 模式相关的特性,
-可实例化一个未代理的普通 TCC 接口实现类, 然后使用 `org.apache.seata.integration.tx.api.util.ProxyUtil` 创建一个代理的TCC接口类,
-并调用 TCC 接口实现类 `Try`,`Confirm`,`Cancel` 三个阶段对应的函数。
+ShardingSphere 的 Seata 集成仅支持 AT 模式。
 
-对于由 Seata TCC 模式而引入的 `org.apache.seata.spring.annotation.GlobalTransactional` 注解或 Seata TCC 模式涉及的业务函数中需要与数据库实例交互,
-此注解标记的业务函数内不应使用 ShardingSphere JDBC DataSource,
-而是应该手动创建`javax.sql.DataSource` 实例,或从自定义的 Spring Bean 中获取 `javax.sql.DataSource` 实例。
+如果应用使用 Seata TCC,请使用不由 ShardingSphere JDBC 管理的独立数据源,并参考 Apache Seata 官方文档配置和调用 TCC API。
 
 ### 跨服务调用的事务传播
 
-跨服务调用场景下的事务传播,并不像单个微服务内的事务操作一样开箱即用。
-对于 Seata Server,跨服务调用场景下的事务传播,要把 XID 通过服务调用传递到服务提供方,并绑定到 `org.apache.seata.core.context.RootContext` 中去。
-参考 https://seata.apache.org/docs/user/api/ 。这需要讨论两种情况,
-
-1. 在使用 ShardingSphere JDBC 的场景下,跨多个微服务的事务场景需要考虑在起点微服务的上下文使用 `org.apache.seata.core.context.RootContext.getXID()` 获取 Seata XID 后,
-   通过 HTTP 或 RPC 等手段传递给终点微服务,并在终点微服务的 Filter 或 Spring WebMVC HandlerInterceptor 中处理。
-   Spring WebMVC HandlerInterceptor 仅适用于 Spring Boot 微服务,对 Quarkus,Micronaut Framework 和 Helidon 无效。
-
-2. 在使用 ShardingSphere Proxy 的场景下,多个微服务均对着 ShardingSphere Proxy 的逻辑数据源操作本地事务,
-   这将在 ShardingSphere Proxy 的服务端来转化为对分布式事务的操作,不需要考虑额外的 Seata XID。
-
-引入简单场景来继续讨论在使用 ShardingSphere JDBC 的场景下,跨服务调用的事务传播。假设存在以下已知微服务和中间件的 Docker Image 实例。
-
-1. MySQL 数据库实例 `a-mysql`,所有 database 均已创建 `UNDO_LOG` 表和业务表。
-2. MySQL 数据库实例 `b-mysql`,所有 database 均已创建 `UNDO_LOG` 表和业务表。
-3. 使用 `file` 作为配置中心和注册中心的 Seata Server 实例 `a-seata-server`。
-4. 微服务实例 `a-service`。此微服务创建仅配置数据库实例 `a-mysql` 的 ShardingSphere JDBC DataSource。
-此 ShardingSphere JDBC DataSource 配置使用连接到 Seata Server 实例 `a-seata-server` 的 Seata AT 集成,其 Seata Application Id 为 `service-a`,
-其 Seata 事务分组为 `default_tx_group`,其 `Virtual Group Mapping` 指向的 Seata Transaction Coordinator 集群分组为 `default`。
-此微服务实例 `a-service` 暴露单个 Restful API 的 GET 端点为 `/hello`,此 Restful API 端点的业务函数 `aMethod` 使用了普通的本地事务注解。
-若此微服务基于 Spring Boot 2,
-
-```java
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class DemoController {
-   @Transactional
-   @GetMapping("/hello")
-   public String aMethod() {
-      // ... 对数据库实例 `a-mysql` 做 UPDATE 操作
-      return "Hello World!";
-   }
-}
-```
-
-5. 微服务实例 `b-service`。此微服务创建仅配置数据库实例 `b-mysql` 的 ShardingSphere JDBC DataSource。
-此 ShardingSphere JDBC DataSource 配置使用连接到 Seata Server 实例 `a-seata-server` 的 Seata AT 集成,其 Seata Application Id 为 `service-b`,
-其 Seata 事务分组为 `default_tx_group`,其 `Virtual Group Mapping` 指向的 Seata Transaction Coordinator 集群分组为 `default`。
-此微服务实例 `b-service` 的业务函数 `bMethod` 使用普通的本地事务注解,并在 `bMethod` 通过 HTTP Client 调用微服务实例 `a-service` 的 `/hello` Restful API 端点。
-若此微服务基于 Spring Boot 2,
-
-```java
-import org.springframework.boot.web.client.RestTemplateBuilder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.RestTemplate;
-
-@Service
-public class DemoService {
-   @Transactional
-   public void bMethod() {
-      RestTemplate restTemplate = new RestTemplateBuilder().build();
-      restTemplate.getForEntity("http://a-service/hello", String.class);
-      // ... 对数据库实例 `b-mysql` 做 UPDATE 操作
-   }
-}
-```
-
-对于此简单场景,此时存在单个 Seata Server Cluster,其包含单个 `Virtual Group` 为 `default`。 此 `Virtual Group` 包含单个 Seata Server 实例为 `a-seata-server`。
-
-讨论单服务调用的事务传播。当微服务实例 `a-service` 的业务函数 `aMethod` 抛出异常,在业务函数内对 MySQL 数据库实例 `a-mysql` 的更改将被正常回滚。
-
-讨论跨服务调用的事务传播。当微服务实例 `b-service` 的业务函数 `bMethod` 抛出异常,在业务函数内对 MySQL 数据库实例 `b-mysql` 的更改将被正常回滚,
-而微服务实例 `a-service` 的 `org.apache.seata.core.context.RootContext` 未绑定微服务实例 `b-service` 的业务函数 `bMethod` 的 Seata XID,
-因此在业务函数内对 MySQL 数据库实例 `a-mysql` 的更改将不会被回滚。
-
-为了实现当微服务实例 `b-service` 的业务函数 `bMethod` 抛出异常,在业务函数内对 MySQL 数据库实例 `a-mysql` 和 `b-mysql` 的更改均被正常回滚,
-讨论不同场景下的常见处理方案。
-
-1. 微服务实例 `a-service` 和 `b-service` 均为基于 Jakarta EE 8 的 Spring Boot 2 微服务。
-用户可在微服务实例 `b-service` 的业务函数 `bMethod` 使用 `org.springframework.web.client.RestTemplate` 把 XID 通过服务调用传递到微服务实例 `a-service`。
-可能的改造逻辑如下。
-
-```java
-import org.apache.seata.core.context.RootContext;
-import org.springframework.boot.web.client.RestTemplateBuilder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.RestTemplate;
-
-@Service
-public class DemoService {
-    @Transactional
-    public void bMethod() {
-        RestTemplate restTemplate = new RestTemplateBuilder().additionalInterceptors((request, body, execution) -> {
-                    String xid = RootContext.getXID();
-                    if (null != xid) {
-                        request.getHeaders().add(RootContext.KEY_XID, xid);
-                    }
-                    return execution.execute(request, body);
-                })
-                .build();
-        restTemplate.getForEntity("http://a-service/hello", String.class);
-        // ... 对数据库实例 `b-mysql` 做 UPDATE 操作
-    }
-}
-```
-
-此时在微服务实例 `a-service` 需要添加自定义的 `org.springframework.web.servlet.config.annotation.WebMvcConfigurer` 实现。
-
-```java
-import org.apache.seata.integration.http.TransactionPropagationInterceptor;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-@Configuration
-public class CustomWebMvcConfigurer implements WebMvcConfigurer {
+ShardingSphere JDBC 的 Seata AT 集成负责使当前 ShardingSphere 数据源上的数据库操作参与 Seata 全局事务。
+该集成不负责在服务之间传播 Seata XID。
 
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new TransactionPropagationInterceptor());
-    }
-}
-```
-
-此时,当微服务实例 `b-service` 的业务函数 `bMethod` 抛出异常,在业务函数内对 MySQL 数据库实例 `a-mysql` 和 `b-mysql` 的更改均被正常回滚。
-
-2. 微服务实例 `a-service` 和 `b-service` 均为基于 Jakarta EE 9/10 的 Spring Boot 3 微服务。
-用户可在微服务实例 `b-service` 的业务函数 `bMethod` 使用 `org.springframework.web.client.RestClient` 把 XID 通过服务调用传递到微服务实例 `a-service`。
-可能的改造逻辑如下。
-
-```java
-import org.apache.seata.core.context.RootContext;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.RestClient;
-
-@Service
-public class DemoService {
-    @Transactional
-    public void bMethod() {
-        RestClient restClient = RestClient.builder().requestInterceptor((request, body, execution) -> {
-                    String xid = RootContext.getXID();
-                    if (null != xid) {
-                        request.getHeaders().add(RootContext.KEY_XID, xid);
-                    }
-                    return execution.execute(request, body);
-                })
-                .build();
-        restClient.get().uri("http://a-service/hello").retrieve().body(String.class);
-        // ... 对数据库实例 `b-mysql` 做 UPDATE 操作
-    }
-}
-```
-
-此时在微服务实例 `a-service` 需要添加自定义的 `org.springframework.web.servlet.config.annotation.WebMvcConfigurer` 实现。
-
-```java
-import org.apache.seata.integration.http.JakartaTransactionPropagationInterceptor;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-@Configuration
-public class CustomWebMvcConfigurer implements WebMvcConfigurer {
-
-   @Override
-   public void addInterceptors(InterceptorRegistry registry) {
-      registry.addInterceptor(new JakartaTransactionPropagationInterceptor());
-   }
-}
-```
-
-此时,当微服务实例 `b-service` 的业务函数 `bMethod` 抛出异常,在业务函数内对 MySQL 数据库实例 `a-mysql` 和 `b-mysql` 的更改均被正常回滚。
-
-3. 微服务实例 `a-service` 和 `b-service` 均为 Spring Boot 微服务,但使用的 API 网关中间件阻断了所有包含 `TX_XID` 的 HTTP Header 的 HTTP 请求。
-用户需要考虑更改把 XID 通过服务调用传递到微服务实例 `a-service` 使用的 HTTP Header,或使用 RPC 框架把 XID 通过服务调用传递到微服务实例 `a-service`。
-参考 https://github.com/apache/incubator-seata/tree/v2.6.0/extensions/rpc 。
-
-4. 微服务实例 `a-service` 和 `b-service` 均为 Quarkus,Micronaut Framework 和 Helidon 等微服务。
-此情况下无法使用 Spring WebMVC HandlerInterceptor。
-可参考如下 Spring Boot 3 的自定义 WebMvcConfigurer 实现,来实现 Filter。
-
-```java
-import org.apache.seata.common.util.StringUtils;
-import org.apache.seata.core.context.RootContext;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.lang.NonNull;
-import org.springframework.web.servlet.HandlerInterceptor;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-@Configuration
-public class CustomWebMvcConfigurer implements WebMvcConfigurer {
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new HandlerInterceptor() {
-            @Override
-            public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
-                String rpcXid = request.getHeader(RootContext.KEY_XID);
-                String xid = RootContext.getXID();
-                if (StringUtils.isBlank(xid) && StringUtils.isNotBlank(rpcXid)) {
-                    RootContext.bind(rpcXid);
-                }
-                return true;
-            }
-            @Override
-            public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {
-                if (RootContext.inGlobalTransaction()) {
-                    String rpcXid = request.getHeader(RootContext.KEY_XID);
-                    String xid = RootContext.getXID();
-                    if (StringUtils.isNotBlank(xid)) {
-                        String unbindXid = RootContext.unbind();
-                        if (!StringUtils.equalsIgnoreCase(rpcXid, unbindXid)) {
-                            if (StringUtils.isNotBlank(unbindXid)) {
-                                RootContext.bind(unbindXid);
-                            }
-                        }
-                    }
-                }
-            }
-        });
-    }
-}
-```
-
-5. 微服务实例 `a-service` 和 `b-service` 均为 Spring Boot 微服务,但使用的组件是 Spring WebFlux 而非 Spring WebMVC。
-在反应式编程 API 下 ShardingSphere JDBC 无法处理 R2DBC DataSource,仅可处理 JDBC DataSource。
-在使用 WebFlux 组件的 Spring Boot 微服务中应避免创建 ShardingSphere JDBC DataSource。
-
-### Log 配置
-
-在业务项目启动 Seata Client 后,可能看到如下的 Error Log。
-
-```shell
-[ERROR] 2024-12-20 11:46:43.878 [ForkJoinPool.commonPool-worker-1] o.a.s.config.ConfigurationFactory - failed to load non-spring configuration :not found service provider for : org.apache.seata.config.ConfigurationProvider
-org.apache.seata.common.loader.EnhancedServiceNotFoundException: not found service provider for : org.apache.seata.config.ConfigurationProvider
-```
+当事务跨越 HTTP、RPC、消息或其他服务边界时,XID 的传递、绑定和清理由应用框架及 Seata Client 负责。
+请根据使用的 Seata 版本和通信框架参考 Apache Seata 官方文档。
 
-根据 https://github.com/apache/incubator-seata/issues/6886 ,抛出此异常是 Seata Client 的预期行为。
-若使用 logback 作为 SLF4J 的实现,用户可通过在业务项目的 classpath 放置 `logback.xml` 对 Seata Client 的日志加以配置。
+ShardingSphere 不规定传输 Header、框架过滤器或拦截器,也不要求应用手动操作 XID 上下文。
diff --git a/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.en.md b/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.en.md
index 6543af34c87..0882a623842 100644
--- a/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.en.md
+++ b/docs/document/content/user-manual/shardingsphere-jdbc/special-api/transaction/seata.en.md
@@ -10,8 +10,8 @@ All references to Seata integration in this article refer to Seata AT mode.
 
 ## Prerequisites
 
-ShardingSphere's Seata integration is only available in `apache/incubator-seata:v2.6.0` or higher.
-For Seata Client corresponding to the `org.apache.seata:seata-all` Maven module, this limitation applies to both HotSpot VM and GraalVM Native Image.
+This document targets Apache Seata 2.6.0.
+Use `org.apache.seata:seata-all:2.6.0` as the Seata Client dependency for both HotSpot VM and GraalVM Native Image.
 Introduce Maven dependencies and exclude the outdated Maven dependency of `org.antlr:antlr4-runtime:4.8` in `org.apache.seata:seata-all`.
 
 ```xml
@@ -37,10 +37,7 @@ Introduce Maven dependencies and exclude the outdated Maven dependency of `org.a
 </project>
 ```
 
-When using ShardingSphere's Seata integration module, 
-the database instance connected to ShardingSphere should implement both ShardingSphere's dialect parsing support and Seata AT mode's dialect parsing support.
-This type of database includes but is not limited to `mysql`, `gvenzl/oracle-free`, `gvenzl/oracle-xe`, `postgres`, 
-`mcr.microsoft.com/mssql/server` and other Docker Images.
+The database must be supported by both ShardingSphere and Seata AT mode.
 
 ### `undo_log` table restrictions
 
@@ -302,27 +299,31 @@ transaction:
    providerType: Seata
 ```
 
-### Enjoy integration
+### Verify transaction rollback
 
-You can start enjoying integration on ShardingSphere’s data source.
+The following example verifies that an unsuccessful transaction is rolled back on the ShardingSphere data source.
 
 ```java
-import com.zaxxer.hikari.HikariConfig;
-import com.zaxxer.hikari.HikariDataSource;
 import java.sql.Connection;
+import java.sql.ResultSet;
 import java.sql.SQLException;
-@SuppressWarnings({"SqlNoDataSourceInspection", "AssertWithSideEffects"})
+import java.sql.Statement;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+@SuppressWarnings("SqlNoDataSourceInspection")
 public class ExampleTest {
     void test() throws SQLException {
         HikariConfig config = new HikariConfig();
         config.setJdbcUrl("jdbc:shardingsphere:classpath:demo.yaml");
         config.setDriverClassName("org.apache.shardingsphere.driver.ShardingSphereDriver");
         try (HikariDataSource dataSource = new HikariDataSource(config)) {
-            try (Connection conn = dataSource.getConnection()) {
+            try (Connection conn = dataSource.getConnection(); Statement statement = conn.createStatement()) {
+                conn.setAutoCommit(false);
+                statement.executeUpdate("INSERT INTO t_order (user_id, order_type, address_id, status) VALUES (2024, 1, 2024, 'INSERT_TEST')");
                 try {
-                    conn.setAutoCommit(false);
-                    conn.createStatement().executeUpdate("INSERT INTO t_order (user_id, order_type, address_id, status) VALUES (2024, 1, 2024, 'INSERT_TEST')");
-                    conn.createStatement().executeUpdate("INSERT INTO t_order_does_not_exist (test_id_does_not_exist) VALUES (2024)");
+                    statement.executeUpdate("INSERT INTO t_order_does_not_exist (test_id_does_not_exist) VALUES (2024)");
                     conn.commit();
                 } catch (final SQLException ignored) {
                     conn.rollback();
@@ -330,8 +331,11 @@ public class ExampleTest {
                     conn.setAutoCommit(true);
                 }
             }
-            try (Connection conn = dataSource.getConnection()) {
-                assert !conn.createStatement().executeQuery("SELECT * FROM t_order_item WHERE user_id = 2024").next();
+            try (Connection conn = dataSource.getConnection(); Statement statement = conn.createStatement();
+                    ResultSet resultSet = statement.executeQuery("SELECT * FROM t_order WHERE user_id = 2024")) {
+                if (resultSet.next()) {
+                    throw new IllegalStateException("Transaction rollback failed.");
+                }
             }
         }
     }
@@ -342,12 +346,10 @@ public class ExampleTest {
 
 ShardingSphere's Seata integration does not support isolation levels.
 
-ShardingSphere's Seata integration places the obtained Seata global transaction into the thread's local variables.
-And `org.apache.seata.spring.annotation.GlobalTransactionScanner` uses Dynamic Proxy to enhance the method.
-This means that when using ShardingSphere's Seata integration, users should avoid using the Java API of `org.apache.seata:seata-all`, 
-unless the user is mixing ShardingSphere's Seata integration with the TCC mode feature of Seata Client.
+ShardingSphere manages the Seata global transaction for its JDBC data source.
+Do not use another global transaction entry point to manage transactions on the same data source.
 
-For ShardingSphere data source, 7 situations are discussed.
+The following rules apply to ShardingSphere data sources.
 
 1. Manually obtain the `java.sql.Connection` instance created from the ShardingSphere data source and manually call the `setAutoCommit()`, `commit()` and `rollback()` methods.
 This is allowed.
@@ -412,266 +414,18 @@ seata:
    enable-auto-data-source-proxy: false
 ```
 
-### Mixed use with Seata TCC mode features
-
-For the case of setting up ShardingSphere's Seata integration,
-In business functions unrelated to ShardingSphere JDBC DataSource, if you need to use Seata Client's Seata TCC mode-related features in business functions,
-you can instantiate a non-proxy ordinary TCC interface implementation class, and then use `org.apache.integration.tx.api.util.ProxyUtil` to create a proxy TCC interface class,
-and call the functions corresponding to the three stages of the TCC interface implementation class `Try`, `Confirm`, and `Cancel`.
-
-For the `org.apache.seata.spring.annotation.GlobalTransactional` annotation introduced by the Seata TCC mode or the business functions involved in the Seata TCC mode that need to interact with the database instance, 
-ShardingSphere JDBC DataSource should not be used in the business functions marked by this annotation. Instead, 
-a `javax.sql.DataSource` instance should be created manually or obtained from a custom Spring Bean.
-
-### Transactional propagation across service calls
-
-Transactional propagationn in cross-service call scenarios is not as out-of-the-box as transaction operations within a single microservice.
-For Seata Server, transactional propagation in cross-service call scenarios requires passing XID to the service provider through service calls and binding it to `org.apache.seata.core.context.RootContext`.
-Refer to https://seata.apache.org/docs/user/api/ . This requires discussing two situations,
-
-1. In the scenario of using ShardingSphere JDBC, 
-transaction scenarios across multiple microservices need to consider using `org.apache.seata.core.context.RootContext.getXID()` to obtain Seata XID in the context of the starting microservice,
-and passing it to the end microservice through HTTP or RPC, and processing it in the Filter or Spring WebMVC HandlerInterceptor of the end microservice.
-Spring WebMVC HandlerInterceptor is only applicable to Spring Boot microservices and is invalid for Quarkus, Micronaut Framework and Helidon.
-
-2. In the scenario of using ShardingSphere Proxy, multiple microservices operate local transactions against the logical data source of ShardingSphere Proxy.
-This will be converted into distributed transaction operations on the server side of ShardingSphere Proxy, without considering additional Seata XID.
-
-Introduce a simple scenario to continue discussing the transactional propagation across service calls in the scenario of using ShardingSphere JDBC.
-
-1. MySQL database instance `a-mysql`, all databases have created `UNDO_LOG` table and business table.
-2. MySQL database instance `b-mysql`, all databases have created `UNDO_LOG` table and business table.
-3. Seata Server instance `a-seata-server` using `file` as configuration center and registration center.
-4. Microservice instance `a-service`. This microservice creates a ShardingSphere JDBC DataSource that only configures the database instance `a-mysql`.
-This ShardingSphere JDBC DataSource configuration uses the Seata AT integration connected to the Seata Server instance `a-seata-server`, 
-whose Seata Application Id is `service-a`, whose Seata transaction group is `default_tx_group`, 
-and the Seata Transaction Coordinator cluster group pointed to by its `Virtual Group Mapping` is `default`.
-This microservice instance `a-service` exposes a single Restful API GET endpoint as `/hello`,
-and the business function `aMethod` of this Restful API endpoint uses a common local transaction annotation.
-If this microservice is based on Spring Boot 2,
-
-```java
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class DemoController {
-   @Transactional
-   @GetMapping("/hello")
-   public String aMethod() {
-      // ... Perform an UPDATE operation on the database instance `a-mysql`
-      return "Hello World!";
-   }
-}
-```
-
-5. Microservice instance `b-service`. This microservice creates a ShardingSphere JDBC DataSource that only configures the database instance `b-mysql`.
-This ShardingSphere JDBC DataSource configuration uses the Seata AT integration connected to the Seata Server instance `a-seata-server`, 
-whose Seata Application Id is `service-b`, whose Seata transaction group is `default_tx_group`, 
-and whose `Virtual Group Mapping` points to the Seata Transaction Coordinator cluster group as `default`.
-The business function `bMethod` of this microservice instance `b-service` uses a normal local transaction annotation, 
-and calls the `/hello` Restful API endpoint of the microservice instance `a-service` through the HTTP Client in `bMethod`.
-If this microservice is based on Spring Boot 2,
-
-```java
-import org.springframework.boot.web.client.RestTemplateBuilder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.RestTemplate;
-
-@Service
-public class DemoService {
-   @Transactional
-   public void bMethod() {
-      RestTemplate restTemplate = new RestTemplateBuilder().build();
-      restTemplate.getForEntity("http://a-service/hello", String.class);
-      // ... Perform an UPDATE operation on the database instance `b-mysql`
-   }
-}
-```
-
-For this simple scenario, there is a single Seata Server Cluster, which contains a single `Virtual Group` as `default`. 
-This `Virtual Group` contains a single Seata Server instance as `a-seata-server`.
-
-Discuss transaction propagation for single service calls. When the business function `aMethod` of the microservice instance `a-service` throws an exception, 
-the changes to the MySQL database instance `a-mysql` in the business function will be rolled back normally.
+### Mixing with other Seata transaction modes
 
-Discuss transaction propagation for cross-service calls. When the business function `bMethod` of the microservice instance `b-service` throws an exception, 
-the changes to the MySQL database instance `b-mysql` in the business function will be rolled back normally,
-and the `org.apache.seata.core.context.RootContext` of the microservice instance `a-service` is not bound to the Seata XID of the business function `bMethod` of the microservice instance `b-service`,
-so the changes to the MySQL database instance `a-mysql` in the business function will not be rolled back.
+ShardingSphere's Seata integration supports AT mode only.
 
-In order to achieve that when the business function `bMethod` of the microservice instance `b-service` throws an exception, 
-the changes to the MySQL database instances `a-mysql` and `b-mysql` in the business function are rolled back normally,
-discuss the common processing solutions in different scenarios.
+If an application uses Seata TCC, use a separate data source that is not managed by ShardingSphere JDBC and follow the Apache Seata documentation for TCC configuration and APIs.
 
-1. The microservice instances `a-service` and `b-service` are both Spring Boot 2 microservices based on Jakarta EE 8.
-Users can use `org.springframework.web.client.RestTemplate` in the business function `bMethod` of the microservice instance `b-service` to pass the XID to the microservice instance `a-service` through the service call.
-The possible transformation logic is as follows.
-
-```java
-import org.apache.seata.core.context.RootContext;
-import org.springframework.boot.web.client.RestTemplateBuilder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.RestTemplate;
-
-@Service
-public class DemoService {
-    @Transactional
-    public void bMethod() {
-        RestTemplate restTemplate = new RestTemplateBuilder().additionalInterceptors((request, body, execution) -> {
-                    String xid = RootContext.getXID();
-                    if (null != xid) {
-                        request.getHeaders().add(RootContext.KEY_XID, xid);
-                    }
-                    return execution.execute(request, body);
-                })
-                .build();
-        restTemplate.getForEntity("http://a-service/hello", String.class);
-        // ... Perform an UPDATE operation on the database instance `b-mysql`
-    }
-}
-```
-
-At this time, a custom `org.springframework.web.servlet.config.annotation.WebMvcConfigurer` implementation needs to be added to the microservice instance `a-service`.
-
-```java
-import org.apache.seata.integration.http.TransactionPropagationInterceptor;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+### Transaction propagation across service calls
 
-@Configuration
-public class CustomWebMvcConfigurer implements WebMvcConfigurer {
+ShardingSphere JDBC's Seata AT integration makes database operations on the current ShardingSphere data source participate in a Seata global transaction.
+It does not propagate the Seata XID between services.
 
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new TransactionPropagationInterceptor());
-    }
-}
-```
-
-At this time, when the business function `bMethod` of the microservice instance `b-service` throws an exception, 
-the changes to the MySQL database instances `a-mysql` and `b-mysql` in the business function are rolled back normally.
-
-2. The microservice instances `a-service` and `b-service` are both Spring Boot 3 microservices based on Jakarta EE 9/10.
-Users can use `org.springframework.web.client.RestClient` in the business function `bMethod` of the microservice instance `b-service` to pass the XID to the microservice instance `a-service` through a service call.
-The possible transformation logic is as follows.
-
-```java
-import org.apache.seata.core.context.RootContext;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.RestClient;
-
-@Service
-public class DemoService {
-    @Transactional
-    public void bMethod() {
-        RestClient restClient = RestClient.builder().requestInterceptor((request, body, execution) -> {
-                    String xid = RootContext.getXID();
-                    if (null != xid) {
-                        request.getHeaders().add(RootContext.KEY_XID, xid);
-                    }
-                    return execution.execute(request, body);
-                })
-                .build();
-        restClient.get().uri("http://a-service/hello").retrieve().body(String.class);
-        // ... Perform an UPDATE operation on the database instance `b-mysql`
-    }
-}
-```
-
-At this time, 
-a custom `org.springframework.web.servlet.config.annotation.WebMvcConfigurer` implementation needs to be added to the microservice instance `a-service`.
-
-```java
-import org.apache.seata.integration.http.JakartaTransactionPropagationInterceptor;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-@Configuration
-public class CustomWebMvcConfigurer implements WebMvcConfigurer {
-
-   @Override
-   public void addInterceptors(InterceptorRegistry registry) {
-      registry.addInterceptor(new JakartaTransactionPropagationInterceptor());
-   }
-}
-```
-
-At this time, when the business function `bMethod` of the microservice instance `b-service` throws an exception, 
-the changes to the MySQL database instances `a-mysql` and `b-mysql` in the business function are rolled back normally.
-
-3. The microservice instances `a-service` and `b-service` are both Spring Boot microservices, 
-but the API gateway middleware used blocks all HTTP requests containing the HTTP Header of `TX_XID`.
-The user needs to consider changing the HTTP Header used to pass XID to the microservice instance `a-service` through service calls, 
-or use the RPC framework to pass XID to the microservice instance `a-service` through service calls.
-Refer to https://github.com/apache/incubator-seata/tree/v2.6.0/extensions/rpc .
-
-4. The microservice instances `a-service` and `b-service` are both microservices such as Quarkus, 
-Micronaut Framework and Helidon. In this case, Spring WebMVC HandlerInterceptor cannot be used.
-You can refer to the following Spring Boot 3 custom WebMvcConfigurer implementation to implement Filter.
-
-```java
-import org.apache.seata.common.util.StringUtils;
-import org.apache.seata.core.context.RootContext;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.lang.NonNull;
-import org.springframework.web.servlet.HandlerInterceptor;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-@Configuration
-public class CustomWebMvcConfigurer implements WebMvcConfigurer {
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new HandlerInterceptor() {
-            @Override
-            public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
-                String rpcXid = request.getHeader(RootContext.KEY_XID);
-                String xid = RootContext.getXID();
-                if (StringUtils.isBlank(xid) && StringUtils.isNotBlank(rpcXid)) {
-                    RootContext.bind(rpcXid);
-                }
-                return true;
-            }
-            @Override
-            public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {
-                if (RootContext.inGlobalTransaction()) {
-                    String rpcXid = request.getHeader(RootContext.KEY_XID);
-                    String xid = RootContext.getXID();
-                    if (StringUtils.isNotBlank(xid)) {
-                        String unbindXid = RootContext.unbind();
-                        if (!StringUtils.equalsIgnoreCase(rpcXid, unbindXid)) {
-                            if (StringUtils.isNotBlank(unbindXid)) {
-                                RootContext.bind(unbindXid);
-                            }
-                        }
-                    }
-                }
-            }
-        });
-    }
-}
-```
-
-5. Both microservice instances `a-service` and `b-service` are Spring Boot microservices, but the components used are Spring WebFlux instead of Spring WebMVC.
-ShardingSphere JDBC cannot handle R2DBC DataSource under the reactive programming API, only JDBC DataSource.
-Avoid creating ShardingSphere JDBC DataSource in Spring Boot microservices using WebFlux components.
-
-### Log Configuration
-
-After starting Seata Client in a business project, you may see the following Error Log.
-
-```shell
-[ERROR] 2024-12-20 11:46:43.878 [ForkJoinPool.commonPool-worker-1] o.a.s.config.ConfigurationFactory - failed to load non-spring configuration :not found service provider for : org.apache.seata.config.ConfigurationProvider
-org.apache.seata.common.loader.EnhancedServiceNotFoundException: not found service provider for : org.apache.seata.config.ConfigurationProvider
-```
+When a transaction crosses an HTTP, RPC, messaging, or other service boundary, the application framework and Seata Client are responsible for propagating, binding, and clearing the XID.
+Follow the Apache Seata documentation for the Seata version and communication framework in use.
 
-According to https://github.com/apache/incubator-seata/issues/6886 , throwing this exception is the expected behavior of Seata Client.
-If logback is used as the implementation of SLF4J, users can configure the Seata Client's logging by placing `logback.xml` in the classpath of their business project.
+ShardingSphere does not prescribe transport headers, framework filters or interceptors, or manual XID context operations.