Spring Alibaba Nacos + Seata 1.4.0搭建使用


在學習springcloud系統繼承seata1.4.0的過程中,踩了不少的坑。因此記錄一下,以便記憶。

 

第一步:搭建Nacos

參考官網:https://nacos.io/zh-cn/docs/quick-start.html

windows環境:

1.下載nacos

下載地址:https://github.com/alibaba/nacos/releases

我選擇的是1.4.0版本

 

2.啟動服務

以單機模式模式啟動:startup.cmd -m standalone

當然也可以修改startup.cmd文件直接點擊啟動

這樣便顯示啟動nacos成功。

訪問:http://localhost:8848/nacos/

出現下圖:

nacos的默認賬號密碼是:nacos/nacos

 

 

第二步:搭建seata環境

1.下載seata

下載地址:https://github.com/seata/seata/releases

我下載的是1.4.0版本

 

2.搭建數據庫

seata-server

搭建seata應用前,需要創建一個數據庫。數據庫名為: seata

但是從seata1.0.0版本(好像是這個)開始,不再自帶數據庫腳本。因此需要下載source文件,或者到github上找。

數據庫腳本地址:https://github.com/seata/seata/blob/develop/script/server/db/mysql.sql

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;
​
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;
​
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(96),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

 

seata-server的數據庫最終是這樣:

seata-client

seata-client為自己測試的服務,可自由發揮。但是每個事務的數據庫中都要添加一張undo_log表。

腳本地址是:https://github.com/seata/seata/blob/develop/script/client/at/db/mysql.sql

-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT(20)   NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(100) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

 

業務表參考:

# 訂單庫
create database seata_order;
​
# 訂單表
CREATE TABLE t_order(
`id` bigint(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`user_id` bigint(20) DEFAULT NULL COMMENT '用戶id',
`product_id` bigint(11) DEFAULT NULL COMMENT '產品id',
`count` int(11) DEFAULT NULL COMMENT '數量',
`money` decimal(11,0) DEFAULT NULL COMMENT '金額',
`status` int(1) DEFAULT NULL COMMENT '訂單狀態:0:創建中1:已完結'
)ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARACTER SET=utf8;
​
​
#庫存庫
create database seata_storage;
​
CREATE TABLE t_storage(
`id` bigint(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`product_id` bigint(11) DEFAULT NULL COMMENT '產品id',
`total` int(11) DEFAULT NULL COMMENT '總庫存',
`used` int(11) DEFAULT NULL COMMENT '已用庫存',
`residue` int(11) DEFAULT NULL COMMENT '剩余庫存'
)ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARACTER SET=utf8;
​
insert into seata_storage.t_storage(`id`,`product_id`,`total`,`used`,`residue`)
values('1','1','100','0','100');
​
​
#賬戶庫
create database seata_account;
​
CREATE TABLE t_account(
`id` bigint(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'id',
`user_id` bigint(11) DEFAULT NULL COMMENT '用戶id',
`total` DECIMAL(10,0) DEFAULT NULL COMMENT '總額度',
`used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余額',
`residue` DECIMAL(10,0) DEFAULT NULL COMMENT '剩余可用額度'
)ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARACTER SET=utf8;
​
insert into seata_account.t_account(`id`,`user_id`,`total`,`used`,`residue`)
values('1','1','1000','0','1000');
 

執行完腳本的效果圖:

3.修改文件配置

config.txt

下載地址:https://github.com/seata/seata/blob/develop/script/config-center/config.txt

修改

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.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=file
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.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=username
store.db.password=password
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.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根目錄下:

nacos-config.sh

下載地址:https://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh

#!/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

 

將該文件復制到seata/conf文件夾下面:

添加config.txt的配置到nacos

注意這里要將config.txt的配置添加到nacos上面,打開git bash here

執行命令:sh nacos-config.sh -h 127.0.0.1

刷新nacos,可以看到config.txt的配置注冊到nacos上面了:

 

file.conf:

找到D:\develop\server\seata\seata-server-1.4.0\seata\conf位置下的file.conf文件修改。必須修改的地方有:

store.mode="db"

store.db.url= "jdbc:mysql://127.0.0.1:3306/seata"

store.db.user = "root"

store.db.password = "123456"

## transaction log store, only used in seata-server
store {
  ## store mode: file、db、redis
  mode = "db"## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
    # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }
​
  ## 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"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "root"
    password = "123456"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
​
  ## redis store property
  redis {
    host = "127.0.0.1"
    port = "6379"
    password = ""
    database = "0"
    minConn = 1
    maxConn = 10
    maxTotal = 100
    queryLimit = 100
  }
​
}

registry.conf

同樣找到D:\develop\server\seata\seata-server-1.4.0\seata\conf位置下的file.conf文件修改。必須修改的地方有:

registry.type="nacos" #因為我用的注冊中心是nacos,所以改為nacos

registry.nacos.username= "nacos"

registry.nacos.password= "nacos"

registry.config.type= "nacos"

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos"
  loadBalance = "RandomLoadBalance"
  loadBalanceVirtualNodes = 10
​
  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "DEFAULT_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = 0
    password = ""
    cluster = "default"
    timeout = 0
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}
​
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"
​
  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = ""
    password = ""
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
    appId = "seata-server"
    apolloMeta = "http://192.168.1.204:8801"
    namespace = "application"
    apolloAccesskeySecret = ""
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 6000
    connectTimeout = 2000
    username = ""
    password = ""
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}

 

4.啟動服務

windows:

直接雙擊seata-server.bat:

成功啟動后,可以在nacos上面看到:

 

第三步:搭建客戶端服務

關於服務端的代碼太多,就貼出關鍵部分的。要想知道全部代碼,可以參考我的github: https://github.com/BestLmc/maomao/tree/master/seata-orader-service2001

OrderService

pom:

<dependencies>
        <!--nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--seata-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>seata-all</artifactId>
                    <groupId>io.seata</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-all</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!--feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--web-actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--mysql-druid-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

 

application.yml

server:
  port: 2001
​
spring:
  application:
    name: seata-order-service
  cloud:
#    alibaba:
#      seata:
#        #自定義事務組名稱需要與seata-server中的對應
#        tx-service-group: default
    nacos:
      discovery:
        server-addr: localhost:8848
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/seata_order
    username: root
    password: 123456
​
seata:
  enabled: true
  application-id: ${spring.application.name}
  enable-auto-data-source-proxy: false
  tx-service-group: SEATA_GROUP
  service:
    vgroupMapping:
      SEATA_GROUP: default
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      group : "SEATA_GROUP"
      namespace: ""
      username: "nacos"
      password: "nacos"
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: ""
      group: SEATA_GROUP
      cluster: default
​
feign:
  hystrix:
    enabled: false
​
logging:
  level:
    io:
      seata: info
​
mybatis:
  mapperLocations: classpath:mapper/*.xml

 

OrderServiceImpl

/**
   * 創建訂單->調用庫存服務扣減庫存->調用賬戶服務扣減賬戶余額->修改訂單狀態
   * 簡單說:下訂單->扣庫存->減余額->改狀態
   */
@Override
@GlobalTransactional(name = "fsp-create-order",rollbackFor = Exception.class)
public void create(Order order)
{
    log.info("----->開始新建訂單");
    //1 新建訂單
    orderDao.create(order);
​
    //2 扣減庫存
    log.info("----->訂單微服務開始調用庫存,做扣減Count");
    storageService.decrease(order.getProductId(),order.getCount());
    log.info("----->訂單微服務開始調用庫存,做扣減end");
​
    //3 扣減賬戶
    log.info("----->訂單微服務開始調用賬戶,做扣減Money");
    accountService.decrease(order.getUserId(),order.getMoney());
    log.info("----->訂單微服務開始調用賬戶,做扣減end");
​
    //4 修改訂單狀態,從零到1,1代表已經完成
    log.info("----->修改訂單狀態開始");
    orderDao.update(order.getUserId(),0);
    log.info("----->修改訂單狀態結束");
​
    log.info("----->下訂單結束了,O(∩_∩)O哈哈~");
​
}

 

啟動服務

啟動相關服務,如圖:

注意:由於測試的時候2002和2003的端口被占用了,因此就改為其他的端口測試。

接下來就可以進行seata的事務測試了!

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM