wanghao 3 месяцев назад
Родитель
Сommit
99e6e99cfb

+ 27 - 21
authentication/src/main/resources/application-dev.yml

@@ -2,14 +2,14 @@ spring:
   cloud:
     nacos:
       server-addr: 192.168.5.250:8848
-      username:
-      password:
+      username: nacos
+      password: nacos
       config:
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 9fceaca4-c1d2-4bb8-aac9-f64d4b7de73c
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 9fceaca4-c1d2-4bb8-aac9-f64d4b7de73c
   config:
     import:
       - nacos:mysql
@@ -18,27 +18,33 @@ spring:
 config:
   sso: 0
 seata:
-  enabled: true
-  application-id: ${spring.application.name}
-  # 事务组的名称,对应service.vgroupMapping.default_tx_group=xxx中配置的default_tx_group
-  tx-service-group: default_tx_group
-  # 配置事务组与集群的对应关系
-  service:
-    vgroup-mapping:
-      # default_tx_group为事务组的名称,default为集群名称(与registry.conf中的一致)
-      default_tx_group: default
-    disable-global-transaction: false
+  enabled: true                                       # 启用Seata分布式事务
+  application-id: ${spring.application.name}          # 应用ID,使用spring应用名
+  tx-service-group: default_tx_group                  # 事务服务组名
+  enable-auto-data-source-proxy: true                 # 自动代理数据源(Seata会自动包装数据源)
   registry:
-    type: nacos
+    type: nacos                                       # 注册中心类型:nacos(从Nacos发现Seata Server)
+    nacos:
+      server-addr: 192.168.5.250:8848                 # Nacos地址
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759 # Nacos命名空间
+      group: SEATA_GROUP                              # 注册分组
+      username: nacos                                 # Nacos用户名
+      password: nacos                                 # Nacos密码
+      application: seata-server                       # Seata Server在Nacos的服务名
+      cluster: default                                # Seata集群名
+  config:
+    type: nacos                                       # 配置中心类型:nacos(从Nacos读取Seata配置)
     nacos:
-      application: seata-server
       server-addr: 192.168.5.250:8848
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
       group: SEATA_GROUP
-      namespace: ba488f58-c785-49b4-9c02-b5d9b8a965a5
-      username:
-      password:
-      # registry.conf中,配置cluster名称
-      cluster: default
+      username: nacos
+      password: nacos
+      data-id: seata.properties                       # Nacos中的配置data-id
+  service:
+    vgroupMapping:
+      default_tx_group: default                       # 事务组映射到Seata Server集群(default集群)
+    disable-global-transaction: false                 # 不禁用全局事务
 wechat:
   open:
     properties:

+ 6 - 2
commons/pom.xml

@@ -136,6 +136,10 @@
             <artifactId>opentelemetry-api</artifactId>
             <version>1.41.0</version>
         </dependency>
+        <dependency>
+            <groupId>io.seata</groupId>
+            <artifactId>seata-spring-boot-starter</artifactId>
+        </dependency>
 
         <!--Gson 转化-->
         <dependency>
@@ -163,8 +167,8 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <configuration>
-                    <source>14</source>
-                    <target>14</target>
+                    <source>17</source>
+                    <target>17</target>
 <!--                    <annotationProcessorPaths>-->
 <!--                        <path>-->
 <!--                            <groupId>org.projectlombok</groupId>-->

+ 6 - 1
commons/src/main/java/com/jzg/commons/config/BaseFeignConfig.java

@@ -1,9 +1,11 @@
 package com.jzg.commons.config;
 
 import feign.RequestInterceptor;
+import io.seata.core.context.RootContext;
 import jakarta.servlet.http.HttpServletRequest;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.util.StringUtils;
 import org.springframework.web.context.request.RequestAttributes;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
@@ -13,7 +15,6 @@ public class BaseFeignConfig {
 
     @Bean
     public RequestInterceptor requestInterceptor() {
-        //拦截器 设置Token
         return requestTemplate -> {
             RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
             if (requestAttributes instanceof ServletRequestAttributes) {
@@ -27,6 +28,10 @@ public class BaseFeignConfig {
                      requestTemplate.header("system_code", systemCode);
                 }
             }
+            String xid = RootContext.getXID();
+            if (StringUtils.hasText(xid)) {
+                requestTemplate.header(RootContext.KEY_XID, xid);
+            }
         };
     }
 

+ 38 - 0
commons/src/main/java/com/jzg/commons/config/SeataXidFilter.java

@@ -0,0 +1,38 @@
+package com.jzg.commons.config;
+
+import io.seata.core.context.RootContext;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class SeataXidFilter implements Filter {
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException {
+        HttpServletRequest httpRequest = (HttpServletRequest) request;
+        String xid = httpRequest.getHeader(RootContext.KEY_XID);
+
+        if (StringUtils.hasText(xid) && !StringUtils.hasText(RootContext.getXID())) {
+            RootContext.bind(xid);
+            try {
+                chain.doFilter(request, response);
+            } finally {
+                RootContext.unbind();
+            }
+        } else {
+            chain.doFilter(request, response);
+        }
+    }
+}

+ 6 - 1
commons/src/main/java/com/jzg/commons/exception/GlobalExceptionHandler.java

@@ -2,16 +2,19 @@ package com.jzg.commons.exception;
 
 import com.jzg.commons.core.page.HttpResult;
 import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.ConstraintViolationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DuplicateKeyException;
+import org.springframework.http.HttpStatus;
 import org.springframework.validation.BindingResult;
 import org.springframework.validation.ObjectError;
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
 
 import java.sql.SQLIntegrityConstraintViolationException;
 import java.util.List;
@@ -84,9 +87,11 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(Exception.class)
     @ResponseBody
-    public HttpResult handleException(HttpServletRequest request, Exception e) {
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    public HttpResult handleException(HttpServletRequest request, HttpServletResponse response, Exception e) {
         String uri = request.getRequestURI();
         String method = request.getMethod();
+        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
         LOGGER.error("【系统异常】接口 [{}],[{}] 出错", method, uri, e);
         return HttpResult.error(500, "程序异常,请联系管理员");
     }

+ 5 - 2
consoleStatistics/src/main/resources/application-dev.yml

@@ -6,10 +6,10 @@ spring:
       password: nacos
       config:
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
   config:
     import:
       - nacos:mysql
@@ -20,6 +20,9 @@ spring:
 config:
   sso: 1
 
+seata:
+  enabled: false
+
 #银联API参数配置
 unionPay:
   api:

+ 5 - 2
gateway/src/main/resources/application-dev.yml

@@ -18,10 +18,10 @@ spring:
         import-check:
           enabled: false
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
 
     gateway:
       routes:
@@ -158,3 +158,6 @@ spring:
                   - /partner/rule/**
                   - /partner/**
                   - /purchaseRecord/**
+
+seata:
+  enabled: false

+ 5 - 2
partner/src/main/resources/application-dev.yml

@@ -6,15 +6,18 @@ spring:
       password:
       config:
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
   config:
     import:
       - nacos:mysql
       - nacos:redisson
 
+seata:
+  enabled: false
+
 
 
 feign:

+ 28 - 18
platform/src/main/resources/application-dev.yml

@@ -8,10 +8,10 @@ spring:
       password: nacos
       config:
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
   config:
     import:
       - nacos:mysql
@@ -24,22 +24,32 @@ config:
 
 
 seata:
-  tx:
-    service:
-      grouplist: 192.168.5.250:8091
-  application-id: platform-service
-  tx-service-group: my_global_tx_group  # 事务服务组
-  enable-auto-data-source-proxy: true  # 启用数据源代理
+  enabled: true                                       # 启用Seata分布式事务
+  application-id: ${spring.application.name}          # 应用ID,使用spring应用名
+  tx-service-group: default_tx_group                  # 事务服务组名
+  enable-auto-data-source-proxy: true                 # 自动代理数据源(Seata会自动包装数据源)
+  registry:
+    type: nacos                                       # 注册中心类型:nacos(从Nacos发现Seata Server)
+    nacos:
+      server-addr: 192.168.5.250:8848                 # Nacos地址
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759 # Nacos命名空间
+      group: SEATA_GROUP                              # 注册分组
+      username: nacos                                 # Nacos用户名
+      password: nacos                                 # Nacos密码
+      application: seata-server                       # Seata Server在Nacos的服务名
+      cluster: default                                # Seata集群名
+  config:
+    type: nacos                                       # 配置中心类型:nacos(从Nacos读取Seata配置)
+    nacos:
+      server-addr: 192.168.5.250:8848
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
+      group: SEATA_GROUP
+      username: nacos
+      password: nacos
+      data-id: seata.properties                       # Nacos中的配置data-id
   service:
-    vgroup-mapping:
-      my_global_tx_group: default  # 事务组与 Seata Server 绑定
-  store:
-    mode: db  # 存储模式,可以是 db 或 file 等
-    db:
-      datasource:
-        driver-class-name: com.mysql.cj.jdbc.Driver
-        url: jdbc:mysql://39.98.239.48:3306/seata
-        username: root
-        password: '@RqGHG#KZ*C9ytkQ'
+    vgroupMapping:
+      default_tx_group: default                       # 事务组映射到Seata Server集群(default集群)
+    disable-global-transaction: false                 # 不禁用全局事务
 
 

+ 24 - 16
platform/src/main/resources/application-prod.yml

@@ -25,22 +25,30 @@ config:
 
 
 seata:
-  tx:
-    service:
-      grouplist: 172.24.144.227:8091
-  application-id: platform-service
-  tx-service-group: my_global_tx_group  # 事务服务组
-  enable-auto-data-source-proxy: true  # 启用数据源代理
+  registry:
+    type: nacos                                       # 注册中心类型:nacos(从Nacos发现Seata Server)
+    nacos:
+      server-addr: 172.24.144.227:8848                # Nacos地址(生产环境)
+      namespace: f9ca025f-b5df-47a9-b3f6-15bcbad3ebd3 # Nacos命名空间(生产环境)
+      group: SEATA_GROUP                              # 注册分组
+      username: nacos                                 # Nacos用户名
+      password: AnrNjNn6zCS3QdIy                      # Nacos密码
+      application: seata-server                       # Seata Server在Nacos的服务名
+      cluster: default                                # Seata集群名
+  config:
+    type: nacos                                       # 配置中心类型:nacos(从Nacos读取Seata配置)
+    nacos:
+      server-addr: 172.24.144.227:8848
+      namespace: f9ca025f-b5df-47a9-b3f6-15bcbad3ebd3
+      group: SEATA_GROUP
+      username: nacos
+      password: AnrNjNn6zCS3QdIy
+      data-id: seata.properties                       # Nacos中的配置data-id
+  application-id: platform-service                    # 应用ID(生产环境固定名称)
+  tx-service-group: my_global_tx_group                # 事务服务组名(生产环境使用独立分组)
+  enable-auto-data-source-proxy: true                 # 自动代理数据源(Seata会自动包装数据源)
   service:
-    vgroup-mapping:
-      my_global_tx_group: default  # 事务组与 Seata Server 绑定
-  store:
-    mode: db  # 存储模式,可以是 db 或 file 等
-    db:
-      datasource:
-        driver-class-name: com.mysql.cj.jdbc.Driver
-        url: jdbc:mysql://39.98.239.48:3306/seata
-        username: root
-        password: '@RqGHG#KZ*C9ytkQ'
+    vgroupMapping:
+      my_global_tx_group: default                     # 事务组映射到Seata Server集群(default集群)
 
 

+ 1 - 1
pom.xml

@@ -284,7 +284,7 @@
       <!--seata-->
       <dependency>
         <groupId>io.seata</groupId>
-        <artifactId>seata-all</artifactId>
+        <artifactId>seata-spring-boot-starter</artifactId>
         <version>${seata.version}</version>
       </dependency>
 

+ 5 - 2
tenant/costsorrule/src/main/resources/application-dev.yml

@@ -6,10 +6,10 @@ spring:
       password:
       config:
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
   config:
     import:
       - nacos:mysql
@@ -17,3 +17,6 @@ spring:
       - nacos:minio
       - nacos:rocketmq
 
+seata:
+  enabled: false
+

+ 16 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/client/SeataTestOrgClient.java

@@ -0,0 +1,16 @@
+package com.jzg.quotation.summary.client;
+
+import com.jzg.commons.core.page.HttpResult;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@FeignClient(name = "jzg-organization", url = "http://localhost:8084/")
+public interface SeataTestOrgClient {
+
+    @GetMapping("/tenant/seataTestWrite")
+    HttpResult<String> seataTestWrite(@RequestParam("name") String name);
+
+    @GetMapping("/tenant/seataTestWriteFail")
+    HttpResult<String> seataTestWriteFail(@RequestParam("name") String name);
+}

+ 70 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/controller/SeataTestController.java

@@ -0,0 +1,70 @@
+package com.jzg.quotation.summary.controller;
+
+import com.jzg.commons.core.page.HttpResult;
+import com.jzg.quotation.summary.client.SeataTestOrgClient;
+import io.seata.core.context.RootContext;
+import io.seata.spring.annotation.GlobalTransactional;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/seataTest")
+public class SeataTestController {
+
+    private static final Logger log = LoggerFactory.getLogger(SeataTestController.class);
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    private SeataTestOrgClient seataTestOrgClient;
+
+    @GetMapping("/success")
+    @GlobalTransactional(rollbackFor = Exception.class)
+    public HttpResult<String> testSuccess(@RequestParam(defaultValue = "test") String name) {
+        String xid = RootContext.getXID();
+        log.info("【quotation-summary 发起方】开启全局事务,XID=[{}]", xid);
+
+        jdbcTemplate.update("INSERT INTO seata_test (name, source) VALUES (?, ?)", name, "quotation-summary");
+        log.info("【quotation-summary 发起方】本地写入成功");
+
+        HttpResult<String> result = seataTestOrgClient.seataTestWrite(name);
+        log.info("【quotation-summary 发起方】远程调用 organization 结果:{}", result);
+
+        return HttpResult.ok("分布式事务测试-成功路径,XID=" + xid + ",org结果=" + result.getMsg());
+    }
+
+    @GetMapping("/rollback")
+    @GlobalTransactional(rollbackFor = Exception.class)
+    public HttpResult<String> testRollback(@RequestParam(defaultValue = "test") String name) {
+        String xid = RootContext.getXID();
+        log.info("【quotation-summary 发起方】开启全局事务(回滚测试),XID=[{}]", xid);
+
+        jdbcTemplate.update("INSERT INTO seata_test (name, source) VALUES (?, ?)", name, "quotation-summary-rollback");
+        log.info("【quotation-summary 发起方】本地写入成功,即将调用 organization 故意失败接口");
+
+        HttpResult<String> remoteResult = null;
+        try {
+            remoteResult = seataTestOrgClient.seataTestWriteFail(name);
+        } catch (Exception e) {
+            log.info("【quotation-summary 发起方】Feign 调用异常:{},分布式事务将回滚", e.getMessage());
+            throw e;
+        }
+
+        // 双重保障:即使 Feign 没抛异常,检查返回码,非 200 也触发回滚
+        if (remoteResult == null || remoteResult.getCode() != 200) {
+            String errMsg = remoteResult != null ? remoteResult.getMsg() : "远程调用返回为空";
+            log.info("【quotation-summary 发起方】远程调用返回错误码 [{}]:{},手动触发回滚",
+                    remoteResult != null ? remoteResult.getCode() : "null", errMsg);
+            throw new RuntimeException("远程调用失败: " + errMsg);
+        }
+
+        return HttpResult.ok("不会走到这里");
+    }
+}

+ 5 - 1
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/controller/UnifyOrderManager.java

@@ -390,7 +390,11 @@ public class UnifyOrderManager {
             log.error("车险报价异常", e);
             Throwable root = e.getCause() != null ? e.getCause() : e;
             String errMsg = root.getMessage() != null ? root.getMessage() : "系统异常,报价失败";
-            insOrdersService.orderAfterUpdateFailedQuote(ordersNo, errMsg);
+            try {
+                insOrdersService.orderAfterUpdateFailedQuote(ordersNo, errMsg);
+            } catch (Exception ex) {
+                log.error("更新报价失败状态异常, ordersNo: {}", ordersNo, ex);
+            }
             throw new SystemException(errMsg);
         }
         return quoteResultsVo.getQuoteStatusEnum()

+ 32 - 2
tenant/insurance/quotation-summary/src/main/resources/application-dev.yaml

@@ -6,10 +6,10 @@ spring:
       password: nacos
       config:
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
   config:
     import:
       - nacos:mysql
@@ -24,6 +24,36 @@ spring:
       port: 6379
       password: 123456  # 如果没有密码,可删除此行
       database: 0
+
+
+seata:
+  enabled: true                                       # 启用Seata分布式事务
+  application-id: ${spring.application.name}          # 应用ID,使用spring应用名
+  tx-service-group: default_tx_group                  # 事务服务组名
+  enable-auto-data-source-proxy: true                 # 自动代理数据源(Seata会自动包装数据源)
+  registry:
+    type: nacos                                       # 注册中心类型:nacos(从Nacos发现Seata Server)
+    nacos:
+      server-addr: 192.168.5.250:8848                 # Nacos地址
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759 # Nacos命名空间
+      group: SEATA_GROUP                              # 注册分组
+      username: nacos                                 # Nacos用户名
+      password: nacos                                 # Nacos密码
+      application: seata-server                       # Seata Server在Nacos的服务名
+      cluster: default                                # Seata集群名
+  config:
+    type: nacos                                       # 配置中心类型:nacos(从Nacos读取Seata配置)
+    nacos:
+      server-addr: 192.168.5.250:8848
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
+      group: SEATA_GROUP
+      username: nacos
+      password: nacos
+      data-id: seata.properties                       # Nacos中的配置data-id
+  service:
+    vgroupMapping:
+      default_tx_group: default                       # 事务组映射到Seata Server集群(default集群)
+
 #百度图片识别API
 baidu:
   clientId: xG9M8tSjNvYPwSTNavM0ELlD

+ 1 - 1
tenant/organization/pom.xml

@@ -55,7 +55,7 @@
 
         <dependency>
             <groupId>io.seata</groupId>
-            <artifactId>seata-all</artifactId>
+            <artifactId>seata-spring-boot-starter</artifactId>
         </dependency>
 
     </dependencies>

+ 32 - 9
tenant/organization/src/main/java/com/jzg/organization/controller/TestController.java

@@ -1,22 +1,45 @@
 package com.jzg.organization.controller;
 
-import com.alibaba.fastjson.JSONObject;
 import com.jzg.commons.core.page.HttpResult;
+import io.seata.core.context.RootContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
 @RequestMapping("/tenant")
 public class TestController {
 
-//    @Autowired
-//    TestClient testClient;
-//
-//    @GetMapping(value = "aa")
-//    public String aa(){
-//        HttpResult userPer = testClient.getUserPer();
-//        return JSONObject.toJSONString(userPer);
-//    }
+    private static final Logger log = LoggerFactory.getLogger(TestController.class);
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @GetMapping("/seataTestWrite")
+    @Transactional(rollbackFor = Exception.class)
+    public HttpResult<String> seataTestWrite(@RequestParam(defaultValue = "test") String name) {
+        String xid = RootContext.getXID();
+        log.info("【organization 参与方】收到请求,XID=[{}], name=[{}]", xid, name);
+
+        jdbcTemplate.update("INSERT INTO seata_test (name, source) VALUES (?, ?)", name, "organization");
+
+        return HttpResult.ok("organization 写入成功, XID=" + xid);
+    }
+
+    @GetMapping("/seataTestWriteFail")
+    @Transactional(rollbackFor = Exception.class)
+    public HttpResult<String> seataTestWriteFail(@RequestParam(defaultValue = "test") String name) {
+        String xid = RootContext.getXID();
+        log.info("【organization 参与方-故意失败】收到请求,XID=[{}], name=[{}]", xid, name);
+
+        jdbcTemplate.update("INSERT INTO seata_test (name, source) VALUES (?, ?)", name, "organization-fail");
+
+        throw new RuntimeException("organization 故意抛出异常,测试分布式事务回滚");
+    }
 }

+ 31 - 2
tenant/organization/src/main/resources/application-dev.yml

@@ -6,10 +6,10 @@ spring:
       password:
       config:
         file-extension: yaml
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
         group: DEFAULT_GROUP
       discovery:
-        namespace: 4efb5e2a-71db-4a19-9550-bb69d437698d
+        namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
   config:
     import:
       - nacos:mysql
@@ -20,6 +20,35 @@ spring:
 config:
   sso: 1
 
+seata:
+  enabled: true                                       # 启用Seata分布式事务
+  application-id: ${spring.application.name}          # 应用ID,使用spring应用名
+  tx-service-group: default_tx_group                  # 事务服务组名
+  enable-auto-data-source-proxy: true                 # 自动代理数据源(Seata会自动包装数据源)
+  registry:
+    type: nacos                                       # 注册中心类型:nacos(从Nacos发现Seata Server)
+    nacos:
+      server-addr: 192.168.5.250:8848                 # Nacos地址
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759 # Nacos命名空间
+      group: SEATA_GROUP                              # 注册分组
+      username: nacos                                 # Nacos用户名
+      password: nacos                                 # Nacos密码
+      application: seata-server                       # Seata Server在Nacos的服务名
+      cluster: default                                # Seata集群名
+  config:
+    type: nacos                                       # 配置中心类型:nacos(从Nacos读取Seata配置)
+    nacos:
+      server-addr: 192.168.5.250:8848
+      namespace: 353f8f05-4d2c-4a17-b64d-b678408f5759
+      group: SEATA_GROUP
+      username: nacos
+      password: nacos
+      data-id: seata.properties                       # Nacos中的配置data-id
+  service:
+    vgroupMapping:
+      default_tx_group: default                       # 事务组映射到Seata Server集群(default集群)
+    disable-global-transaction: false                 # 不禁用全局事务
+
 feign:
   client:
     quotation-summary: