zoukankan      html  css  js  c++  java
  • 使用tx-lcn完成分布式事务管理

      TxManager是LCN分布式事务框架的事务协调器,框架基于Netty做消息通讯,事务控制数据存储在redis中。

    TxManager采用高可用集群化部署方案,多个TM通过eureka集群完成服务注册,各个TxClient通过服务名称向TxManager发送事务信息。

    一、搭建TxManager

    1、创建一个springboot项目

    继承父项目

    <parent>
            <groupId>com.zl.stock</groupId>
            <artifactId>stock-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../stock-parent/pom.xml</relativePath>
    </parent>

    导入相关依赖

    <!--添加Eureka-client的依赖 -->
     <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- tx-lcn的事务协调器依赖 -->
    <dependency>
          <groupId>com.codingapi.txlcn</groupId>
          <artifactId>txlcn-tm</artifactId>
           <version>5.0.2.RELEASE</version>
    </dependency>
    <!--目前只支持mysql记录日志--><dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    2、在启动类上添加注解,@EnableTransactionManagerServer

    @SpringBootApplication
    @EnableTransactionManagerServer
    @EnableEurekaClient
    public class StockTxmanagerApplication {。。}

    4、保留默认配置文件application.properties(无内容)

    新建一个application.yml文件进行配置

    3、配置yml配置文件

    #配置端口
    server:
    port: 8521
    #redis相关配置
    spring:
      profiles:
        active: dev
      redis:
        host: 127.0.0.1
        port: 6381
      application:
        name: stock-txManager
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver 
        url: jdbc:mysql://localhost:3306/tx-manager?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      jpa:
        database-platform: org.hibernate.dialect.MySQL5InnoDBDialect  # 数据库方言
        hibernate.ddl-auto: update  #第一次运行可以设置为: create, 为TM创建持久化数据库表
    
    #eureka相关配置
    eureka:
      instance:
        hostname: 127.0.0.1
        #修改eureka-client在注册中心页面显示的名字
        #${spring.cloud.client.ipaddress} 获取服务的ip地址
        instance-id: stock-txManager-${spring.cloud.client.ipaddress}-${server.port}
        #服务信息显示的真实的ip, 开发中一定要设置为true, 如果不设置, 其他电脑访问不到你的服务
        prefer-ip-address: true
      client:
        serviceUrl:
          defaultZone: http://${eureka.instance.hostname}:10001/eureka/
    
    tx-lcn:
      manager:
        host: 127.0.0.1 # tx-manager ip(client请求ip)
        port: 8070  # client 请求端口
        heart-time: 12000 # 心跳检测时间 单位:ms
        dtx-time: 3000 # 事务执行总时间
        admin-key: 123456 #TM后台登陆密码,默认密码是codingapi
      logger:
        enabled: true #开启日志,默认为false,开发阶段最好开启日志,并设置为debug等级,这样方便追踪排查问题
        #日志记录表 t_logger
        driver-class-name: ${spring.datasource.driver-class-name}
        jdbc-url: ${spring.datasource.url}
        username: ${spring.datasource.username}
        password: ${spring.datasource.password}
    logging:
      level:
        com:
          codingapi:
            txlcn: DEBUG  #日志输出级别

    创建成启动Eureka , 在启动TxManager服务  (默认端口为7970)

     启动成功访问:http://127.0.0.1:7970/   (默认密码为codingapi,修改的密码为123456

     二、创建mysql数据库、表来保存日志

    1、创建MySQL数据库, 名称为:tx-manager

    2、创建数据表:创建异常记录表, 根据tx-lcn的TxException类来创建,表名为: t_tx_exception

    创表语句

    CREATE TABLE `t_tx_exception`  (
      `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
      `group_id` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      `unit_id` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      `mod_id` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      `transaction_state` TINYINT(4) NULL DEFAULT NULL,
      `registrar` TINYINT(4) NULL DEFAULT NULL,
      `remark` VARCHAR(4096) NULL DEFAULT  NULL,
      `ex_state` TINYINT(4) NULL DEFAULT NULL COMMENT '0 未解决 1已解决',
      `create_time` DATETIME NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = INNODB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;

     三、搭建tx-client,就是需要用到的服务(1、调用者、2、被调用者)

    1、在业务服务项目添加相关依赖

    <!-- tx-lcn的client相关依赖 -->
    <dependency>
        <groupId>com.codingapi.txlcn</groupId>
        <artifactId>txlcn-tc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.codingapi.txlcn</groupId>
        <artifactId>txlcn-txmsg-netty</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    2、启动类添加 @EnableDistributedTransaction。

    //本地事务
    @EnableTransactionManagement
    //分布式事务
    @EnableDistributedTransaction

    3、添加yml配置文件

    tx-lcn:
      ribbon:
        loadbalancer:
          dtx:
            enabled: true
      # 默认之配置为TM的本机默认端口
      client:
        manager-address: 127.0.0.1:8070
      # 开启日志,默认为false
      logger:
        enabled: true
        driver-class-name: com.mysql.cj.jdbc.Driver 
        jdbc-url: jdbc:mysql://localhost:3306/tx-manager?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456

    4、在用到事务的service中添加注解(需要添加两个服务我们命名为A、B关系(A调用B))

    A中需要事务的地方添加
    @LcnTransaction(分布式事务)
    @Transactional(本地事务)
    在B中需要事务的地方添加
    @LcnTransaction
    @Transactional

    测试

    A服务调用B服务

    1、在A服务的ServletImpl中:

    //给审核开户信息手动分配一个账号(账号使用时间戳获取)TODO 加上分布式事务
        @Override
        @LcnTransaction//分布式事务
        @Transactional//本地事务
        public boolean byCard(T_realuser realuser) throws Exception {
            //随机生成一个十位的账号
            String id = String.valueOf(Long.parseLong(String.valueOf(System.currentTimeMillis())
                        .substring(1,10).concat(String.valueOf(0))));
           // String timer = new Date().getTime()+"";
            realuser.setAccountid(id);
            realuser.setUpdatetime(new Date());
    
            //修改user表中的激活状态 ** (B服务中的方法)
            userClientService.updateUserStatus(realuser.getRusid());
            return getBaseMapper().updateById(realuser) >0 ?true :false;
        }

    2、在B服务被调用的ServletImpl中:

    //审核通过将状态列改为1
        @Override
        @LcnTransaction//分布式事务
        @Transactional//本地事务
        public boolean updateUserStatus(T_user user) throws Exception {
            //修改时间
            user.setUpdatetime(new Date());
            //修改状态
            user.setStatus(1);
            //自定义异常,测试分布式事务是否成功 -- 查看是否回滚
            int a = 10/0;
            return getBaseMapper().updateById(user) >0 ?true :false;
        }

    3、执行方法

     报错,查看数据库是否更改数据

    数据库中:两张表的数据库都没有进行更改

    4、查看mysql错误日志

     5、也可以在TxManager系统后台中查看错误日志

  • 相关阅读:
    谈谈toLocaleString()
    如何理解NaN?
    Element--->>>最新骨架屏Skeleton使用
    自定义select组件
    微信小程序之配置业务域名踩过的坑
    Vue watch监听 date中的变量 与 数组或者对象的数据变化
    Vue + Element table的@select方法获取当table中的id值都相同时,获取他们索引
    Vue + Element table中的某行触发enter事件后,使该行disabled
    Vue + Element tree树形控件的懒加载使用
    Vue web使用LeapFTP 上传到服务器
  • 原文地址:https://www.cnblogs.com/64Byte/p/13426818.html
Copyright © 2011-2022 走看看