天天看点

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 都是一样的。

如果不一样,你配置的有问题