Seata1.3 + Zookeeper +Dubbo

Seata1.3 + Zookeeper +Dubbo 整合

Seata下载

注:以下AT模式,其他模式还在熟悉,因为AT模式是最简单的

源码版本

  • 建立数据库 SEATA ,AT 模式需要 UNDO_LOG 表;每个和业务相关的库都要有一张 UNDO_LOG 表,后续打断点调试,能看到里面的暂存数据

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for branch_table
-- ----------------------------
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table`  (
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `transaction_id` bigint(20) NULL DEFAULT NULL,
  `resource_group_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `resource_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `lock_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `branch_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `status` tinyint(4) NULL DEFAULT NULL,
  `client_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `application_data` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_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_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for global_table
-- ----------------------------
DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table`  (
  `xid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `transaction_id` bigint(20) NULL DEFAULT NULL,
  `status` tinyint(4) NOT NULL,
  `application_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `transaction_service_group` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `transaction_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `timeout` int(11) NULL DEFAULT NULL,
  `begin_time` bigint(20) NULL DEFAULT NULL,
  `application_data` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_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_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for lock_table
-- ----------------------------
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table`  (
  `row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `transaction_id` mediumtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
  `branch_id` mediumtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
  `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `pk` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_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 = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) 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(11) 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;

SET FOREIGN_KEY_CHECKS = 1;


  • 源码导入idea 报错:
    io.seata.codec.protobuf.generated不存在 !
    解决方案:本地执行
    ./mvnw clean install -DskipTests=true (Mac,Linux) 或 mvnw.cmd clean install -DskipTests=true (Win)
    这个官网有讲到!!!!

  • 修改script/config-center/下的 config.txt 文件
    主要修改 store.mode=db 以及数据库的连接信息
    下边这行代码是重点
    service.vgroupMapping.doushanglai-service_tx_group=default
    旧版本是vgroup_mapping,新版本是 vgroupMapping
    如果看的帖子太多,配置文件新老掺和在一起的话要注意

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.doushanglai-service_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.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
store.mode=db
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=hikari
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://192.168.0.162:3306/seata?useUnicode=true
store.db.user=seata
store.db.password=&Seata12
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.host=127.0.0.1
store.redis.port=6379
store.redis.maxConn=10
store.redis.minConn=1
store.redis.database=0
store.redis.password=null
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.log.exceptionRate=100
transport.serialization=seata
transport.compressor=none
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

  • 启动注册中心,把seata 配置写入到注册中心
    如果你本地的注册中心用的nacos,在seata项目下的script/
    config-center/ 下 执行脚本。
sh nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 5a3c7d6c-f497-4d68-a71a-2e5e3340b3ca -u username -   w password

这一步是把seata 的配置写进注册中心,项目此模块下的 md文档上有写。
nacos的话应该按照文档来, 一套流程走到底。

重点本人用的 Zk,同样执行上边的脚本命令

zk-config.sh -h localhost -p 2181 -z "/Users/zhangchenghui/zookeeper-3.4.14

这个脚本命令执行后,在Zk的节点上只看到了 /seata 节点,下边的子节点全是空的。
所以怀疑1.3 的zk.sh 脚本有问题,仅仅是怀疑,也可能是我自己没搞好,解决方案,代码如下:

代码写入 seata 节点(拷贝别人的)

import com.google.common.base.Charsets;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkMarshallingError;
import org.I0Itec.zkclient.serialize.ZkSerializer;
import org.apache.zookeeper.CreateMode;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Set;

public class ZkDataInit {
    
    
    private static volatile ZkClient zkClient;

    public static void main(String[] args) {
    
    
        if (zkClient == null) {
    
    
            zkClient = new ZkClient("127.0.0.1:2181", 6000, 2000);
            zkClient.setZkSerializer(new ZkSerializer() {
    
    
                @Override
                public byte[] serialize(Object o) throws ZkMarshallingError {
    
    
                    return String.valueOf(o).getBytes(Charsets.UTF_8);
                }

                @Override
                public Object deserialize(byte[] bytes) throws ZkMarshallingError {
    
    
                    return new String(bytes, Charsets.UTF_8);
                }
            });
        }
        if (!zkClient.exists("/seata")) {
    
    
            zkClient.createPersistent("/seata", true);
        }
        //获取key对应的value值
        Properties properties = new Properties();
        // 使用ClassLoader加载properties配置文件生成对应的输入流
        // 使用properties对象加载输入流
        try {
    
    
            File file=new File("C:\\Users\\zjj\\Desktop\\seata-1.3.0\\script\\config-center\\config.txt");
            InputStream in = new FileInputStream(file);
            properties.load(in);
            Set<Object> keys = properties.keySet();
            for (Object key : keys) {
    
    
                putConfig(key.toString(), properties.get(key).toString());
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
/**
     * @param dataId
     * @param content
     * @return
     */
    public static boolean putConfig(final String dataId, final String content) {
    
    
        Boolean flag = false;
        String path = "/seata/" + dataId;
        if (!zkClient.exists(path)) {
    
    
            zkClient.create(path, content, CreateMode.PERSISTENT);
            flag = true;
        } else {
    
    
            zkClient.writeData(path, content);
            flag = true;
        }
        return flag;
    }

运行完之后,查看zk的 /seata 节点下是否有子节点,如图所示就对了
正确的节点

  • 修改seata-server 下的 file.conf 和 registry.conf
    主要修改mode以及数据库连接信息和注册方式

    file.conf

## transaction log store, only used in seata-server
store {
    
    
  ## store mode: file、db、redis
  mode = "db"

  ## database store property
  db {
    
    
    datasource = "hikari"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://192.168.0.162:3306/seata"
    user = "seata"
    password = "&Seata12"
    minConn = 5
    maxConn = 30
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

registry.conf

registry {
    
    
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "zk"
  zk {
    
    
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 60000
    connectTimeout = 20000
    username = ""
    password = ""
  }
  file {
    
    
    name = "file.conf"
  }
}

config {
    
    
  # file、nacos 、apollo、zk、consul、etcd3
  type = "zk"

  zk {
    
    
    serverAddr = "127.0.0.1:2181"
    sessionTimeout = 60000
    connectTimeout = 20000
    username = ""
    password = ""
  }

  file {
    
    
    name = "file.conf"
  }
}
  • 以上确保配置没有问题,启动Server main() 直接启动
    如果有一连串的getconfig 错误 检查 注册中心节点是否配置成功
  • 项目配置

springboot配置

seata:
  enabled: true
  application-id: ${
    
    spring.application.name}
  tx-service-group: doushanglai-service_tx_group
  enable-auto-data-source-proxy: true
  config:
    type: zk
    zk:
      serverAddr: 127.0.0.1:2181
  registry:
    type: zk
    zk:
      application: ${
    
    spring.application.name}
      server-addr: 127.0.0.1:2181

启动dubbo A服务 和 B服务

A启动成功。。。
B启动成功

测试代码如下

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public JsonResult test() {
    
    
        System.out.println("开始全部事务============================》");
        goodsService.test();
        LambdaUpdateWrapper<Task> l = Wrappers.lambdaUpdate();
        Task t = new Task();
        t.setGoodsId(999L);
        this.baseMapper.update(t, l);
        throw new RuntimeException("测试报错");
    }
    @Override
    public JsonResult test() {
    
    
        System.out.println("进入商品TEST事务之前=======================================》》》");
        LambdaUpdateWrapper<Goods> u = Wrappers.lambdaUpdate();
        Goods g = new Goods();
        g.setStock("200");
        this.baseMapper.update(g, u);
        System.out.println("进入商品TEST事务之后=======================================》》》");
        return null;
    }
    @PostMapping("test")
    @ApiOperation(value = "测试分布式事务【A调用B,A抛异常,AB数据都回滚】", notes = "测试分布式事务【A调用B,A抛异常,AB数据都回滚】", produces = "application/json")
    public JsonResult detailAuthFeeList() {
    
    
        return JsonResult.buildResult(taskService.test());
    }

结果A服务 Log在这里插入图片描述

B服务 Log

在这里插入图片描述

数据库数据 goods表

在这里插入图片描述

Task表

在这里插入图片描述

可以在调用端打断点,观察数据库表数据的变化,还有seata 几张表的数据变化,这样更容易理解点。

初步使用已经成功,还在更深入的了解中

配置参考:官方教学

总结:

  1. 注册中心的seata配置要确定没问题,才能往下继续进行,其他注册中心没试过,seata 源码zookeeper 的写配置的脚本一直写不成功
  2. config.txt 里 service.vgroupMapping.doushanglai-service_tx_group=default 的 doushanglai-service_tx_group 配置啥样的 项目对应的服务配置就要写成啥样,修改完config.text的内容后要重新把节点写入一下注册中心(zk,其他注册中心不是很清楚)
  3. seata no available service ‘null’ found, please make sure registry config correct 这个错误检查 上边的service.vgroupMapping.doushanglai-service_tx_group=default 是否正确,是否能在注册中心的节点上找到
  4. 项目结构不一样,所以仅供参考

期间踩了不少坑,因为网上帖子看的太多了,有点乱 这里也感谢Q群:513650703 群主和群员的帮忙 人少 闲话不多,全聊技术。替群主宣传一波

猜你喜欢

转载自blog.csdn.net/zhaojunjie_cc/article/details/108398297
今日推荐