springcloud分布式事务_springcloud整合分布式事务框架LCN

00a151e7276d8eaf13fc23769dd96fdc.png
  • TX-LCN 主要有两个模块,Tx-Client(TC) Tx-Manager(TM). TC作为微服务下的依赖,TM是独立的服务。
  • LCN原理如下
  • 创建事务组
    是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。
  • 加入事务组
    添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息通知给TxManager的操作。
  • 通知事务组
    是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager,TxManager将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方。
  1. 首先我们需要二个微服务项目订单服务和会员服务,订单服务通过feign客户端调用会员服务,不清楚的可以参考上一篇文章:一叶知秋:springcloud整合注册中心和feign客户端简单教程。
  2. 首先整合TM

a 创建MySQL数据库, 名称为: tx-manager,创建数据表

      
   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(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

b 官网下载codingapi/tx-lcn源码和demo:https://github.com/codingapi/txlcn-demo

用idea的maven插件打包源码包TM项目txlcn-tm,txlcn-demo-tm项目的pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>txlcn-demo</artifactId>
        <groupId>org.txlcn.demo</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>txlcn-demo-tm</artifactId>

    <name>txlcn-demo-tm</name>

    <dependencies>
        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tm</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
</project>

c txlcn-demo-tm项目的application.properties文件如下,注意要配置自己的数据库和redis

的地址以及将txlcn-demo-tm注册到eureka中

##################
# 这个是启动本服务的配置文件,其它的application-xxx.properties 是开发者的个性化配置,不用关心。
# 你可以在 https://txlcn.org/zh-cn/docs/setting/manager.html 看到所有的个性化配置
#################

spring.application.name=TransactionManager
server.port=7970
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.137.129: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

redis.database=0
redis.host=127.0.0.1
redis.port=6379
redis.password=
redis.jedis.pool.max-active=50
redis.jedis.pool.max-wait=-1
redis.jedis.pool.max-idle=50
redis.jedis.pool.min-idle=1
redis.timeout=10000

mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true

eureka.client.serviceUrl.defaultZone=http://localhost:8600/eureka/
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
  • 订单项目和会员项目需要整合Tx-Client(TC)
  • 订单项目pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.liwen</groupId>
		<artifactId>parent</artifactId>
		<version>1.0-SNAPSHOT</version>
		<relativePath>../parent</relativePath>
	</parent>
	<groupId>com.liwen</groupId>
	<artifactId>order-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>order-service</name>
	<description>Demo project for Spring Boot</description>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<dependency>
			<groupId>com.liwen</groupId>
			<artifactId>member-service-api</artifactId>
			<version>1.0-SNAPSHOT</version>
		</dependency>
		<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>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.29</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
    </dependencies>
</project>
  • 订单项目配置文件
spring:
  application:
    name: member-service
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://192.168.137.129:3306/member?useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver

server:
  port: 9200

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8600/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
#微服务和TM的通讯地址
tx-lcn:
   client.manager-address: 127.0.0.1:8070


  • 订单项目项目启动类
package com.liwen;

import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
//分布式事务直注解
@EnableDistributedTransaction
public class MemberServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(MemberServiceApplication.class, args);
	}

}
  • 订单项目调用会员项目
package com.liwen.service;

import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.liwen.entity.Member;
import com.liwen.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
public class MemberService implements IMemberService{

    @Autowired
    private MemberRepository memberRepository;

    @LcnTransaction //分布式事务注解
    @Transactional
    @Override
    public String saveMemberMember() {
        Member member = new Member();
        member.setId(null);
        member.setMyName("lwp");
        member.setTime(new Date());
        Member save = memberRepository.save(member);
        int i= 1/0;
        System.out.println("会员服务被调用。。。。。");
        return "SUCCESS";
    }
 }
  • 会员项目pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>com.liwen</groupId>
		<artifactId>parent</artifactId>
		<version>1.0-SNAPSHOT</version>
		<relativePath>../parent</relativePath>
	</parent>

	<groupId>com.liwen</groupId>
	<artifactId>member-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>member-service</name>
	<description>Demo project for Spring Boot</description>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>com.liwen</groupId>
			<artifactId>member-service-api</artifactId>
			<version>1.0-SNAPSHOT</version>
		</dependency>
		<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>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.29</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>

</project>

会员项目配置

spring:
  application:
    name: member-service
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://192.168.137.129:3306/member?useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver

server:
  port: 9200

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8600/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}

tx-lcn:
   client.manager-address: 127.0.0.1:8070
  • 会员项目启动类
package com.liwen;

import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
@EnableDistributedTransaction
public class MemberServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(MemberServiceApplication.class, args);
	}

}
  • 会员项目全局捕获异常
package com.liwen;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

	@ExceptionHandler(RuntimeException.class)
	@ResponseBody
	public JSONObject exceptionHandler(Exception e) {
		log.info("###全局捕获异常###,error:{}", e);
		JSONObject result = new JSONObject();
		result.put("code", 500);
		result.put("msg", "系统错误");
		return result;
	}
}
  • 会员项目提供给订单服务的接口
package com.liwen.service;

import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.liwen.entity.Member;
import com.liwen.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
public class MemberService implements IMemberService{

    @Autowired
    private MemberRepository memberRepository;

    @LcnTransaction //分布式事务注解
    @Transactional
    @Override
    public String saveMemberMember() {
        Member member = new Member();
        member.setId(null);
        member.setMyName("lwp");
        member.setTime(new Date());
        Member save = memberRepository.save(member);
        int i= 1/0;
        System.out.println("会员服务被调用。。。。。");
        return "SUCCESS";
    }
}
  • 下面依次启动注册中心、txlcn-demo-tm、订单项目、会员项目

14d43670e39445419717e59677a641de.png

8638595b14064fd128a628466577f576.png
调用订单服务

订单服务调用会员服务,订单服务是事务发起方,会员服务是事务参与方,会员服务返回500错误,订单服务根据错误码判断,抛出异常,订单服务和会员服务回滚事务。查询数据库订单表和会员表都没有保存数据,与预期一致。

不足之处,望大佬指点,点赞加关注,鼓励一下!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值