天天看點

springcloud 整合TX-LCN實作分布式事務

建立一個項目Tm 項目

springcloud 整合TX-LCN實作分布式事務

導包pom

<!-- 參照例子引入需要的依賴jar -->
        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tm</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
           

注意 jdbc 包必須依賴 不然啟動報錯

配置檔案

spring.application.name=txlcn-tm
server.port=7970

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/tx-manager?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true

# TM背景登陸密碼
tx-lcn.manager.admin-key=123456

tx-lcn.manager.host=127.0.0.1
tx-lcn.manager.port=8070

# 開啟日志,預設為false
tx-lcn.logger.enabled=true
tx-lcn.logger.driver-class-name=${spring.datasource.driver-class-name}
tx-lcn.logger.jdbc-url=${spring.datasource.url}
tx-lcn.logger.username=${spring.datasource.username}
tx-lcn.logger.password=${spring.datasource.password}
logging.level.com.codingapi.txlcn=DEBUG

#redis 主機
spring.redis.host=127.0.0.1
#redis 端口
spring.redis.port=6379
#redis 密碼
spring.redis.password=123456
           

啟動類注解

import com.codingapi.txlcn.tm.config.EnableTransactionManagerServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : WangCong
 * @create 2020/5/9 15:23
 */
@SpringBootApplication
@EnableTransactionManagerServer
public class TxLcnTmApplication {
    public static void main(String[] args) {
        SpringApplication.run(TxLcnTmApplication.class,args);
    }
}
           

建立資料庫表

springcloud 整合TX-LCN實作分布式事務

然後建立表

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;
           

這個Tm 服務就弄好了,啟動。

在其他 要用到分布式事務的項目 中 引入包

比如我 一個提供者 項目和一個消費者項目 都要引入

這是提供者的pom

<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>
           

啟動類

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : WangCong
 * @create 2020/5/7 15:26
 */
//注冊服務到注冊中心去
@EnableDiscoveryClient
@SpringBootApplication
@EnableBinding(MessageService.class)
//開啟分布式事務
@EnableDistributedTransaction
@EnableTransactionManagement
public class ProviderRun {
    public static void main(String[] args) {
        SpringApplication.run(ProviderRun.class, args);
    }
}
           

服務代碼

@Service
public class SysServiceImpl implements SysService {
    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * @LcnTransaction//分布式事務
     * @Transactional //本地事務
     * @param sysUser
     * @return
     */
    @Override
    @LcnTransaction(propagation = DTXPropagation.SUPPORTS)
    @Transactional
    public int add(SysUser sysUser) {
        String groupId = TracingContext.tracing().groupId();
        String applicationId = Transactions.getApplicationId();
        System.out.println(groupId);
        System.out.println(applicationId);
        return sysUserMapper.add(sysUser);
    }
}
           

關于DTXPropagation源碼裡面有解釋

/**
     * 目前沒有分布式事務,就建立。目前有分布式事務,就加入
     */
    REQUIRED,
 
    /**
     * 目前沒有分布式事務,非分布式事務運作。目前有分布式事務,就加入
     */
    SUPPORTS;
           

是以一般事物發起方使用REQUIRED,事物參與方使用SUPPORTS

這裡因為 我是在消費者項目中調用的提供者的服務 ,這裡的是 事物參與方 使用SUPPORTS

配置檔案

server:
  port: 8081
spring:
  profiles:
    include: dev
  application:
    name: provider1
eureka:
  client:
    serviceUrl:
      defaultZone: http://eurka-server2-8060:8060/eureka/,http://eurka-server1-8080:8080/eureka/
  instance:
    #eureka伺服器在接收到最後一個心跳之後等待的時間,然後才能從清單中删除此執行個體 預設90s(開發環境)
    lease-expiration-duration-in-seconds: 10
    #eureka用戶端需要向eureka伺服器發送心跳的頻率 預設30s (開發環境)
    lease-renewal-interval-in-seconds: 1
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    preferIpAddress: true
tx-lcn:
  client:
    manager-address: 127.0.0.1:8070
  springcloud:
    loadbalance:
      enabled: true
           

微服務叢集且用到 LCN事務模式時,為保證性能請開啟TX-LCN重寫的負載政策

tx-lcn.springcloud.loadbalance.enabled=true
           

消費者的pom

<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>
           

啟動類

import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * Created by IntelliJ IDEA.
 * 注解@SpringCloudApplication包括:@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker,分别是SpringBoot注解、注冊服務中心Eureka注解、斷路器注解
 * @Author : WangCong
 * @create 2020/5/9 9:47
 */
@SpringCloudApplication
@EnableFeignClients
//開啟分布式事務
@EnableDistributedTransaction
@EnableTransactionManagement
public class FeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class,args);
    }
}
           

配置檔案

server:
  port: 8084
spring:
  profiles:
    include: dev
  application:
    name: feign1
eureka:
  client:
    serviceUrl:
      defaultZone: http://eurka-server2-8060:8060/eureka/,http://eurka-server1-8080:8080/eureka/
      #healthcheck:
      enabled: true  #開啟自定義健康檢查
  instance:
    #eureka伺服器在接收到最後一個心跳之後等待的時間,然後才能從清單中删除此執行個體 預設90s(開發環境)
    lease-expiration-duration-in-seconds: 10
    #eureka用戶端需要向eureka伺服器發送心跳的頻率 預設30s (開發環境)
    lease-renewal-interval-in-seconds: 1
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    preferIpAddress: true
#開啟hystrix 熔斷
feign:
  hystrix:
    enabled: true
tx-lcn:
  client:
    manager-address: 127.0.0.1:8070
  springcloud:
    loadbalance:
      enabled: true
           

調用提供者代碼

@RequestMapping("/add")
    @Transactional
    @LcnTransaction
    public String test2(){
        String groupId = TracingContext.tracing().groupId();
        String applicationId = Transactions.getApplicationId();
        System.out.println(groupId);
        System.out.println(applicationId);
        SysUser user = new SysUser();
        user.setCreateTime(new Date());
        user.setPassword("123");
        user.setUsername("asdasd");
        user.setSalt("asas");
        user.setStatus(0);
        helloService.list(user);
        user.setUsername("xixixi");
        List list=new ArrayList();
        System.out.println(list.get(23));
        int add = sysUserMapper.add(user);
        return add+"";
    }
           

這裡我使用的是feign 的遠端調用方式

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : WangCong
 * @create 2020/5/9 9:58
 */

/**
 * 遠端服務名稱 可以大小寫
 */
@FeignClient(value = "provider1",fallbackFactory = TestFeignFallbackFactory.class)
public interface HelloService {

    @RequestMapping("/service/hello")
    public String hello();
    @RequestMapping("/service/hello1")
    public String hello1();
    @RequestMapping("/list")
    public String list(@RequestBody SysUser user);
}
           

是以在熔斷的配置注意

熔斷配置

import com.codingapi.txlcn.tc.support.DTXUserControls;
import com.codingapi.txlcn.tracing.TracingContext;
import com.wc.springcloud.model.SysUser;
import com.wc.springcloud.service.HelloService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : WangCong
 * @create 2020/5/9 10:26
 */
@Component
public class TestFeignFallbackFactory implements FallbackFactory<HelloService> {

    @Override
    public HelloService create(Throwable throwable) {
        return new HelloService() {
            @Override
            public String hello() {
                return throwable.getMessage();
            }

            @Override
            public String hello1() {
                return throwable.getMessage();
            }

            @Override
            public String list(SysUser user) {
                //復原事務
                DTXUserControls.rollbackGroup(TracingContext.tracing().groupId());
                return throwable.getMessage();
            }
        };
    }
}
           

注意這句話DTXUserControls.rollbackGroup(TracingContext.tracing().groupId());

如果沒有配置,出現異常 事務不會復原。

運作測試

springcloud 整合TX-LCN實作分布式事務
springcloud 整合TX-LCN實作分布式事務

提供者代碼異常

springcloud 整合TX-LCN實作分布式事務
springcloud 整合TX-LCN實作分布式事務

檢視資料庫 事務復原

springcloud 整合TX-LCN實作分布式事務

注意

我之前代碼 提供者 和消費者

springcloud 整合TX-LCN實作分布式事務

提供者列印輸出的是

springcloud 整合TX-LCN實作分布式事務

消費者列印輸出的是

springcloud 整合TX-LCN實作分布式事務

第一個是組id,第二個是 每個服務的應用辨別

兩邊的組id 都是一樣的。

如果不一樣,你配置的有問題