美文网首页
springcloud+seata+nacos 示例

springcloud+seata+nacos 示例

作者: _Rondo | 来源:发表于2021-08-16 15:52 被阅读0次
    前言

    项目中用到了微服务,因为用到了spring全家桶,分布式事务选型选了seata方便集成,默认采用at模式,这里简单的集成下springboot+nacos+seata。
    项目链接https://github.com/wenxpro/distributed 的seata子项目

    seata-server准备

    下载seata-server1.4.2 最近github网速奇差,建议开代理更改register.conf中的nacos配置

     nacos {
        application = "seata-server"
        serverAddr = "127.0.0.1:8848"
        group = "SEATA_GROUP"
        namespace = "6547a5ca-0b49-4055-99d3-637636995e74"
        cluster = "default"
        username = "nacos"
        password = "nacos"
      }
    

    更改file.conf中的存储模式与db配置

    store {
      ## store mode: file、db、redis
      mode = "db"
       ## database store property
      db {
        ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
        datasource = "druid"
        ## mysql/oracle/postgresql/h2/oceanbase etc.
        dbType = "mysql"
        #driverClassName = "com.mysql.jdbc.Driver"
        driverClassName = "com.mysql.cj.jdbc.Driver"
        ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
        url = "jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8"
        user = "root"
        password = "admin"
        minConn = 5
        maxConn = 100
        globalTable = "global_table"
        branchTable = "branch_table"
        lockTable = "lock_table"
        queryLimit = 100
        maxWait = 5000
      }
    }
    

    https://github.com/seata/seata/tree/develop/script 下可以找到你需要的配置这里下载config.txt 与 nacos-config.sh到seata-server/config下

    #!/usr/bin/env bash
    # Copyright 1999-2019 Seata.io Group.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at、
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    while getopts ":h:p:g:t:u:w:" opt
    do
      case $opt in
      h)
        host=$OPTARG
        ;;
      p)
        port=$OPTARG
        ;;
      g)
        group=$OPTARG
        ;;
      t)
        tenant=$OPTARG
        ;;
      u)
        username=$OPTARG
        ;;
      w)
        password=$OPTARG
        ;;
      ?)
        echo " USAGE OPTION: $0 [-h host] [-p port] [-g group] [-t tenant] [-u username] [-w password] "
        exit 1
        ;;
      esac
    done
    
    urlencode() {
      for ((i=0; i < ${#1}; i++))
      do
        char="${1:$i:1}"
        case $char in
        [a-zA-Z0-9.~_-]) printf $char ;;
        *) printf '%%%02X' "'$char" ;;
        esac
      done
    }
    
    if [[ -z ${host} ]]; then
        host=localhost
    fi
    if [[ -z ${port} ]]; then
        port=8848
    fi
    if [[ -z ${group} ]]; then
        group="SEATA_GROUP"
    fi
    if [[ -z ${tenant} ]]; then
        tenant=""
    fi
    if [[ -z ${username} ]]; then
        username=""
    fi
    if [[ -z ${password} ]]; then
        password=""
    fi
    
    nacosAddr=$host:$port
    contentType="content-type:application/json;charset=UTF-8"
    
    echo "set nacosAddr=$nacosAddr"
    echo "set group=$group"
    
    failCount=0
    tempLog=$(mktemp -u)
    function addConfig() {
      curl -X POST -H "${contentType}" "http://$nacosAddr/nacos/v1/cs/configs?dataId=$(urlencode $1)&group=$group&content=$(urlencode $2)&tenant=$tenant&username=$username&password=$password" >"${tempLog}" 2>/dev/null
      if [[ -z $(cat "${tempLog}") ]]; then
        echo " Please check the cluster status. "
        exit 1
      fi
      if [[ $(cat "${tempLog}") =~ "true" ]]; then
        echo "Set $1=$2 successfully "
      else
        echo "Set $1=$2 failure "
        (( failCount++ ))
      fi
    }
    
    count=0
    for line in $(cat $(dirname "$PWD")/config.txt | sed s/[[:space:]]//g); do
      (( count++ ))
        key=${line%%=*}
        value=${line#*=}
        addConfig "${key}" "${value}"
    done
    
    echo "========================================================================="
    echo " Complete initialization parameters,  total-count:$count ,  failure-count:$failCount "
    echo "========================================================================="
    
    if [[ ${failCount} -eq 0 ]]; then
        echo " Init nacos config finished, please start seata-server. "
    else
        echo " init nacos config fail. "
    fi
    

    修改config.txt 添加几个自己的分组
    service.vgroupMapping.storage-service-group=default
    service.vgroupMapping.order-service-group=default

    transport.type=TCP
    transport.server=NIO
    transport.heartbeat=true
    transport.enableClientBatchSendRequest=false
    transport.threadFactory.bossThreadPrefix=NettyBoss
    transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
    transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
    transport.threadFactory.shareBossWorker=false
    transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
    transport.threadFactory.clientSelectorThreadSize=1
    transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
    transport.threadFactory.bossThreadSize=1
    transport.threadFactory.workerThreadSize=default
    transport.shutdown.wait=3
    service.vgroupMapping.my_test_tx_group=default
    service.vgroupMapping.storage-service-group=default
    service.vgroupMapping.order-service-group=default
    service.default.grouplist=127.0.0.1:8091
    service.enableDegrade=false
    service.disableGlobalTransaction=false
    client.rm.asyncCommitBufferLimit=10000
    client.rm.lock.retryInterval=10
    client.rm.lock.retryTimes=30
    client.rm.lock.retryPolicyBranchRollbackOnConflict=true
    client.rm.reportRetryCount=5
    client.rm.tableMetaCheckEnable=false
    client.rm.tableMetaCheckerInterval=60000
    client.rm.sqlParserType=druid
    client.rm.reportSuccessEnable=false
    client.rm.sagaBranchRegisterEnable=false
    client.tm.commitRetryCount=5
    client.tm.rollbackRetryCount=5
    client.tm.defaultGlobalTransactionTimeout=60000
    client.tm.degradeCheck=false
    client.tm.degradeCheckAllowTimes=10
    client.tm.degradeCheckPeriod=2000
    store.mode=db
    store.publicKey=""
    store.file.dir=file_store/data
    store.file.maxBranchSessionSize=16384
    store.file.maxGlobalSessionSize=512
    store.file.fileWriteBufferCacheSize=16384
    store.file.flushDiskMode=async
    store.file.sessionReloadReadSize=100
    store.db.datasource=druid
    store.db.dbType=mysql
    store.db.driverClassName=com.mysql.cj.jdbc.Driver
    store.db.url=jdbc:mysql://127.0.0.1:3306/seata?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
    store.db.user=root
    store.db.password=admin
    store.db.minConn=5
    store.db.maxConn=30
    store.db.globalTable=global_table
    store.db.branchTable=branch_table
    store.db.queryLimit=100
    store.db.lockTable=lock_table
    store.db.maxWait=5000
    store.redis.mode=single
    store.redis.single.host=127.0.0.1
    store.redis.single.port=6379
    store.redis.sentinel.masterName=sentinel
    store.redis.sentinel.sentinelHosts=localhost:8080
    store.redis.maxConn=10
    store.redis.minConn=1
    store.redis.maxTotal=100
    store.redis.database=0
    store.redis.password="" 
    store.redis.queryLimit=100
    server.recovery.committingRetryPeriod=1000
    server.recovery.asynCommittingRetryPeriod=1000
    server.recovery.rollbackingRetryPeriod=1000
    server.recovery.timeoutRetryPeriod=1000
    server.maxCommitRetryTimeout=-1
    server.maxRollbackRetryTimeout=-1
    server.rollbackRetryTimeoutUnlockEnable=false
    client.undo.dataValidation=true
    client.undo.logSerialization=jackson
    client.undo.onlyCareUpdateColumns=true
    server.undo.logSaveDays=7
    server.undo.logDeletePeriod=86400000
    client.undo.logTable=undo_log
    client.undo.compress.enable=true
    client.undo.compress.type=zip
    client.undo.compress.threshold=64k
    log.exceptionRate=100
    transport.serialization=seata
    transport.compressor=none
    metrics.enabled=false
    metrics.registryType=compact
    metrics.exporterList=prometheus
    metrics.exporterPrometheusPort=9898
    

    seata-server/config下执行

    sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 6547a5ca-0b49-4055-99d3-637636995e74
     -u nacos -w nacos
    

    执行完毕后,windows下点击bin/seata-server.bat运行seata-server

    项目示例

    参考seata-example项目示例,https://gitee.com/seata-io/seata-samples
    父级项目seata

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>seata</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>seata</name>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.2.RELEASE</version>
            <relativePath/>
        </parent>
        <modules>
            <module>order</module>
            <module>storage</module>
        </modules>
    
        <properties>
            <springboot.verison>2.4.2.RELEASE</springboot.verison>
            <java.version>1.8</java.version>
            <mybatis.version>2.1.5</mybatis.version>
            <seata.version>1.3.0</seata.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.11</version>
            </dependency>
    
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.1.1</version>
            </dependency>
        </dependencies>
    
        <!--demo01父模块中添加依赖-->
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>5.1.39</version>
                </dependency>
    
                <dependency>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                    <version>3.1.1</version>
                </dependency>
    
                <dependency>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                    <version>1.1.0</version>
                </dependency>
    
                <!--SpringCloud-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Hoxton.SR9</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
    
                <!--Spring Alibaba Cloud-->
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>2.2.1.RELEASE</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    </project>
    
    

    order项目

    
    ```<?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>com.example</groupId>
            <artifactId>seata</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
        <groupId>com.example</groupId>
        <artifactId>order</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>order</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <!--子模块order-service和storage-service的pom中添加nacos和seata依赖-->
        <dependencies>
    
            <!--nacos注册中心和配置中心-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-spring-boot-starter</artifactId>
                <version>1.3.0</version>
                <exclusions>
                    <exclusion>
                        <groupId>io.seata</groupId>
                        <artifactId>seata-all</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>io.seata</groupId>
                <artifactId>seata-all</artifactId>
                <version>1.3.0</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
                <version>2.2.1.RELEASE</version>
                <exclusions>
                    <exclusion>
                        <groupId>io.seata</groupId>
                        <artifactId>seata-spring-boot-starter</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <!--openfeign-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-okhttp</artifactId>
                <version>10.2.3</version>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.20</version>
                <scope>compile</scope>
            </dependency>
    
        </dependencies>
    
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    Order

    @Data
    @Accessors(chain = true)
    @TableName("order_tbl")
    public class Order {
    
      @TableId(type=IdType.AUTO)
      private Integer id;
      private String userId;
      private String commodityCode;
      private Integer count;
      private BigDecimal money;
    
    }
    
    @Mapper
    @Repository
    public interface OrderDAO extends BaseMapper<Order> {
    
    }
    
    @FeignClient(name = "storage-service")
    public interface StorageFeignClient {
    
        @GetMapping("storage/deduct")
        Boolean deduct(@RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);
    }
    
    @Service
    public class OrderService {
    
        @Resource
        private AccountFeignClient accountFeignClient;
        @Resource
        private StorageFeignClient storageFeignClient;
        @Resource
        private OrderDAO orderDAO;
    
    
        /**
         * 下单:创建订单、减库存,涉及到两个服务
         *
         * @param userId
         * @param commodityCode
         * @param count
         */
        @GlobalTransactional
        @Transactional(rollbackFor = Exception.class)
        public void placeOrder(String userId, String commodityCode, Integer count) {
            BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5));
            Order order = new Order()
                    .setUserId(userId)
                    .setCommodityCode(commodityCode)
                    .setCount(count)
                    .setMoney(orderMoney);
            orderDAO.insert(order);
            storageFeignClient.deduct(commodityCode, count);
    
        }
    
    
        @Transactional(rollbackFor = Exception.class)
        public void create(String userId, String commodityCode, Integer count) {
    
            BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5));
    
            Order order = new Order()
                    .setUserId(userId)
                    .setCommodityCode(commodityCode)
                    .setCount(count)
                    .setMoney(orderMoney);
            orderDAO.insert(order);
    
            accountFeignClient.reduce(userId, orderMoney);
    
        }
    
    }
    
    @RestController
    @RequestMapping("order")
    public class OrderController {
    
        @Resource
        private OrderService orderService;
        @Resource
        private StorageFeignClient storageFeignClient;
    
    
        /**
         * 下单:插入订单表、扣减库存,模拟回滚
         *
         * @return
         */
        @RequestMapping("/placeOrder/commit")
        public Boolean placeOrderCommit() {
    
            orderService.placeOrder("1", "product-1", 1);
            return true;
        }
    
        /**
         * 下单:插入订单表、扣减库存,模拟回滚
         *
         * @return
         */
        @RequestMapping("/placeOrder/rollback")
        public Boolean placeOrderRollback() {
            // product-2 扣库存时模拟了一个业务异常,
            orderService.placeOrder("1", "product-2", 1);
            return true;
        }
    
    
        @RequestMapping("/placeOrder")
        public Boolean placeOrder(String userId, String commodityCode, Integer count) {
            orderService.placeOrder(userId, commodityCode, count);
            return true;
        }
    }
    
    @MapperScan("com.example.order.repository")
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class OrderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    
    }
    
    

    用到的配置文件

    server.port=8864
    
    spring.application.name=order-service
    # Nacos 注册中心地址
    spring.cloud.nacos.discovery.server-addr=localhost:8848
    
    # seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应
    seata.tx-service-group=order-service-group
    seata.enable-auto-data-source-proxy=true
    seata.registry.type=nacos
    seata.registry.nacos.server-addr=localhost:8848
    seata.registry.nacos.namespace=6547a5ca-0b49-4055-99d3-637636995e74
    seata.registry.nacos.group=SEATA_GROUP
    seata.config.type=nacos
    seata.config.nacos.server-addr=localhost:8848
    seata.config.nacos.namespace=6547a5ca-0b49-4055-99d3-637636995e74
    seata.config.nacos.group=SEATA_GROUP
    
    
    
    logging.level.io.seata = debug
    
    
    # 数据源配置
    spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/order?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
    spring.datasource.username=root
    spring.datasource.password=admin
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    
    

    Storage项目

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>seata</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>seata</name>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.2.RELEASE</version>
            <relativePath/>
        </parent>
        <modules>
            <module>order</module>
            <module>storage</module>
        </modules>
    
        <properties>
            <springboot.verison>2.4.2.RELEASE</springboot.verison>
            <java.version>1.8</java.version>
            <mybatis.version>2.1.5</mybatis.version>
            <seata.version>1.3.0</seata.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.10</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.11</version>
            </dependency>
    
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.1.1</version>
            </dependency>
        </dependencies>
    
        <!--demo01父模块中添加依赖-->
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>5.1.39</version>
                </dependency>
    
                <dependency>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                    <version>3.1.1</version>
                </dependency>
    
                <dependency>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                    <version>1.1.0</version>
                </dependency>
    
                <!--SpringCloud-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Hoxton.SR9</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
    
                <!--Spring Alibaba Cloud-->
                <dependency>
                    <groupId>com.alibaba.cloud</groupId>
                    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                    <version>2.2.1.RELEASE</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    </project>
    
    

    Storage

    @Data
    @Accessors(chain = true)
    @TableName("storage_tbl")
    public class Storage {
    
      private Long id;
      private String commodityCode;
      private Long count;
    
    
    }
    
    @Mapper
    @Repository
    public interface StorageDAO extends BaseMapper<Storage> {
    
    }
    
    @Service
    public class StorageService {
    
        @Resource
        private StorageDAO storageDAO;
    
        /**
         * 减库存
         * 
         * @param commodityCode
         * @param count
         */
        @Transactional(rollbackFor = Exception.class)
        public void deduct(String commodityCode, int count) {
            if (commodityCode.equals("product-2")) {
                throw new RuntimeException("异常:模拟业务异常:Storage branch exception");
            }
    
            QueryWrapper<Storage> wrapper = new QueryWrapper<>();
            wrapper.setEntity(new Storage().setCommodityCode(commodityCode));
            Storage storage = storageDAO.selectOne(wrapper);
            storage.setCount(storage.getCount() - count);
    
            storageDAO.updateById(storage);
        }
    }
    
    @RestController
    @RequestMapping("storage")
    public class StorageController {
    
        @Resource
        private StorageService storageService;
    
        /**
         * 减库存
         * @param commodityCode 商品代码
         * @param count 数量
         * @return
         */
        @RequestMapping(path = "/deduct")
        public Boolean deduct(String commodityCode, Integer count) {
            storageService.deduct(commodityCode, count);
            return true;
        }
    
    }
    
    

    用到的配置文件大同小异

    server.port=8865
    
    spring.application.name=storage-service
    # Nacos 注册中心地址
    spring.cloud.nacos.discovery.server-addr=localhost:8848
    
    # seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应
    seata.tx-service-group=storage-service-group
    seata.enable-auto-data-source-proxy=true
    seata.registry.type=nacos
    seata.registry.nacos.server-addr=localhost:8848
    seata.registry.nacos.namespace=6547a5ca-0b49-4055-99d3-637636995e74
    seata.registry.nacos.group=SEATA_GROUP
    seata.config.type=nacos
    seata.config.nacos.server-addr=localhost:8848
    seata.config.nacos.namespace=6547a5ca-0b49-4055-99d3-637636995e74
    seata.config.nacos.group=SEATA_GROUP
    
    
    logging.level.io.seata = debug
    
    
    # 数据源配置
    spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/storage?characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
    spring.datasource.username=root
    spring.datasource.password=admin
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    
    

    启动后调用请求分别模拟成功与回滚
    http://localhost:8864/order/placeOrder/commit
    http://localhost:8864/order/placeOrder/rollback
    并可以在cmd中看到seata-server成功与回滚日志

    image.png
    image.png
    用到的sql
    
    -- ----------------------------
    -- Table structure for storage_tbl
    -- ----------------------------
    DROP TABLE IF EXISTS `storage_tbl`;
    CREATE TABLE `storage_tbl`  (
      `id` int(0) NOT NULL AUTO_INCREMENT,
      `commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `count` int(0) NULL DEFAULT 0,
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `commodity_code`(`commodity_code`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of storage_tbl
    -- ----------------------------
    INSERT INTO `storage_tbl` VALUES (1, 'product-1', 9999997);
    INSERT INTO `storage_tbl` VALUES (2, 'product-2', 0);
    
    -- ----------------------------
    -- Table structure for undo_log
    -- ----------------------------
    DROP TABLE IF EXISTS `undo_log`;
    CREATE TABLE `undo_log`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT,
      `branch_id` bigint(0) NOT NULL,
      `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `rollback_info` longblob NOT NULL,
      `log_status` int(0) NOT NULL,
      `log_created` datetime(0) NOT NULL,
      `log_modified` datetime(0) NOT NULL,
      `ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for branch_table
    -- ----------------------------
    DROP TABLE IF EXISTS `branch_table`;
    CREATE TABLE `branch_table`  (
      `branch_id` bigint(0) NOT NULL,
      `xid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
      `transaction_id` bigint(0) NULL DEFAULT NULL,
      `resource_group_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `resource_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `lock_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `branch_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `status` tinyint(0) NULL DEFAULT NULL,
      `client_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `application_data` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `gmt_create` datetime(0) NULL DEFAULT NULL,
      `gmt_modified` datetime(0) NULL DEFAULT NULL,
      PRIMARY KEY (`branch_id`) USING BTREE,
      INDEX `idx_xid`(`xid`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of branch_table
    -- ----------------------------
    
    -- ----------------------------
    -- Table structure for global_table
    -- ----------------------------
    DROP TABLE IF EXISTS `global_table`;
    CREATE TABLE `global_table`  (
      `xid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
      `transaction_id` bigint(0) NULL DEFAULT NULL,
      `status` tinyint(0) NOT NULL,
      `application_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `transaction_service_group` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `transaction_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `timeout` int(0) NULL DEFAULT NULL,
      `begin_time` bigint(0) NULL DEFAULT NULL,
      `application_data` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `gmt_create` datetime(0) NULL DEFAULT NULL,
      `gmt_modified` datetime(0) NULL DEFAULT NULL,
      PRIMARY KEY (`xid`) USING BTREE,
      INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE,
      INDEX `idx_transaction_id`(`transaction_id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of global_table
    -- ----------------------------
    
    -- ----------------------------
    -- Table structure for lock_table
    -- ----------------------------
    DROP TABLE IF EXISTS `lock_table`;
    CREATE TABLE `lock_table`  (
      `row_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
      `xid` varchar(96) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `transaction_id` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL,
      `branch_id` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL,
      `resource_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `table_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `pk` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
      `gmt_create` datetime(0) NULL DEFAULT NULL,
      `gmt_modified` datetime(0) NULL DEFAULT NULL,
      PRIMARY KEY (`row_key`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of lock_table
    -- ----------------------------
    
    -- ----------------------------
    -- Table structure for undo_log
    -- ----------------------------
    DROP TABLE IF EXISTS `undo_log`;
    CREATE TABLE `undo_log`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT,
      `branch_id` bigint(0) NOT NULL,
      `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `rollback_info` longblob NOT NULL,
      `log_status` int(0) NOT NULL,
      `log_created` datetime(0) NOT NULL,
      `log_modified` datetime(0) NOT NULL,
      `ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for order_tbl
    -- ----------------------------
    DROP TABLE IF EXISTS `order_tbl`;
    CREATE TABLE `order_tbl`  (
      `id` int(0) NOT NULL AUTO_INCREMENT,
      `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `count` int(0) NULL DEFAULT 0,
      `money` int(0) NULL DEFAULT 0,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of order_tbl
    -- ----------------------------
    INSERT INTO `order_tbl` VALUES (1, '1', 'product-1', 1, 5);
    INSERT INTO `order_tbl` VALUES (4, '1', 'product-1', 1, 5);
    
    -- ----------------------------
    -- Table structure for undo_log
    -- ----------------------------
    DROP TABLE IF EXISTS `undo_log`;
    CREATE TABLE `undo_log`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT,
      `branch_id` bigint(0) NOT NULL,
      `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `rollback_info` longblob NOT NULL,
      `log_status` int(0) NOT NULL,
      `log_created` datetime(0) NOT NULL,
      `log_modified` datetime(0) NOT NULL,
      `ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    

    -end-

    相关文章

      网友评论

          本文标题:springcloud+seata+nacos 示例

          本文链接:https://www.haomeiwen.com/subject/iugmbltx.html