Lcn分布式事务流程实现(启动事务协调者)

如果觉得还可以 记得关注一下公众号哦!一起交流学习!

一、lcn流程图实现

二、Lcn介绍

1. tx-lcn

1.正如官网所说的:LCN并不生产事务,LCN只是本地事务的协调工!

Lcn本身不会产生事务,也不会涉及到某些业务代码!他对事务的操作本身就依赖一个事务协调者服务

如上图所说的一样 他分为4个步骤

  1. 服务发起者 在事务协调者内创建事务组,并将本事务加入事务组
  2. 事务参与者加入事务组,直到有结束标记出现
  3. 事务协调者向所有的事务参与者发送询问,是否能够提交!全部提交则事务组提交!有一个回滚标记则事务组回滚!
  4. 事务组执行操作之后,释放所有锁资源!

三、代码案例

1 创建数据库 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;

2.引入事务协调者,并启动

github:https://github.com/codingapi/tx-lcn.git

将标记的项目加入IDEA,并修改配置文件

spring.application.name=tx-manager
server.port=7970spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=rootmybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true#tx-lcn.logger.enabled=true
# TxManager Host Ip
#tx-lcn.manager.host=127.0.0.1
# TxClient连接请求端口
#tx-lcn.manager.port=8070
# 心跳检测时间(ms)
#tx-lcn.manager.heart-time=15000
# 分布式事务执行总时间
#tx-lcn.manager.dtx-time=30000
#参数延迟删除时间单位ms
#tx-lcn.message.netty.attr-delay-time=10000
#tx-lcn.manager.concurrent-level=128
# 开启日志
#tx-lcn.logger.enabled=true
#logging.level.com.codingapi=debug
#redis 主机
#spring.redis.host=127.0.0.1
#redis 端口
#spring.redis.port=6379
#redis 密码
#spring.redis.password=

以上的配置详情介绍

spring.application.name=TransactionManager
server.port=7970# JDBC 数据库配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456# 数据库方言
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect# 第一次运行可以设置为: create, 为TM创建持久化数据库表
spring.jpa.hibernate.ddl-auto=validate# TM监听IP. 默认为 127.0.0.1
tx-lcn.manager.host=127.0.0.1# TM监听Socket端口. 默认为 ${server.port} - 100
tx-lcn.manager.port=8070# 心跳检测时间(ms). 默认为 300000
tx-lcn.manager.heart-time=300000# 分布式事务执行总时间(ms). 默认为36000
tx-lcn.manager.dtx-time=8000# 参数延迟删除时间单位ms  默认为dtx-time值
tx-lcn.message.netty.attr-delay-time=${tx-lcn.manager.dtx-time}# 事务处理并发等级. 默认为机器逻辑核心数5倍
tx-lcn.manager.concurrent-level=160# TM后台登陆密码,默认值为codingapi
tx-lcn.manager.admin-key=codingapi# 分布式事务锁超时时间 默认为-1,当-1时会用tx-lcn.manager.dtx-time的时间
tx-lcn.manager.dtx-lock-time=${tx-lcn.manager.dtx-time}# 雪花算法的sequence位长度,默认为12位.
tx-lcn.manager.seq-len=12# 异常回调开关。开启时请制定ex-url
tx-lcn.manager.ex-url-enabled=false# 事务异常通知(任何http协议地址。未指定协议时,为TM提供内置功能接口)。默认是邮件通知
tx-lcn.manager.ex-url=/provider/email-to/***@**.com# 开启日志,默认为false
tx-lcn.logger.enabled=true
tx-lcn.logger.enabled=false
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}# redis 的设置信息. 线上请用Redis Cluster
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=

3 启动事务协调者

Lcn案例编写

一、上个文章里面已经启动了事务协调者 现在我们来开发一个demo来测试一下协调者是否生效了吧!

一、编写数据库

分别在两个不同的库中创建两张表

CREATE DATABASE /*!32312 IF NOT EXISTS*/`server1` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */;USE `server1`;SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for server1
-- ----------------------------
DROP TABLE IF EXISTS `server1`;
CREATE TABLE `server1`  (`id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;CREATE DATABASE /*!32312 IF NOT EXISTS*/`server2` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */;USE `server2`;
-- ----------------------------
-- Table structure for server2
-- ----------------------------
DROP TABLE IF EXISTS `server2`;
CREATE TABLE `server2`  (`id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

二、父项目pom

pom文件

<?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"><modelVersion>4.0.0</modelVersion><groupId>com.lcn</groupId><artifactId>lcn-test</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>server1</module><module>public-resources</module><module>server2</module><module>eureka</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.1.RELEASE</version></parent><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Finchley.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--spring boot的核心启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
</project>

三、Eureka编写

pom文件

<?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>lcn-test</artifactId><groupId>com.lcn</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.lcn</groupId><artifactId>eureka</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies></project>

配置文件 application.yml

server:port: 8761
spring:application:name: eureka-servereureka:server:peer-eureka-nodes-update-interval-ms: 60000enable-self-preservation: falseeviction-interval-timer-in-ms: 5000client:service-url:defaultZone: http://localhost:8761/eureka/register-with-eureka: falsefetch-registry: true

启动类

package com.eureka.server;import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;/*** @author huangfu*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {public static void main(String[] args) {new SpringApplicationBuilder(EurekaServer.class).run(args);}
}

四、创建公共资源 module(public-resources)

创建serve1实体类

package com.pojo;import lombok.Data;/*** @author huangfu*/
@Data
public class ServerOne {private String id;private String name;public ServerOne() {}public ServerOne(String id, String name) {this.id = id;this.name = name;}
}

创建server2

package com.pojo;import lombok.Data;/*** @author huangfu*/
@Data
public class ServerTwo {private String id;private String name;public ServerTwo() {}public ServerTwo(String id, String name) {this.id = id;this.name = name;}
}

项目结构

五、Server1开发

配置文件 appplication.yml

server:port: 8080spring:application:name: server1main:allow-bean-definition-overriding: truedatasource:driver-class-name:  com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/lcn-server1?useUnicode=true&characterEncoding=utf8username: rootpassword: rooteureka:client:service-url:defaultZone: http://localhost:8761/eureka/instance:prefer-ip-address: truefeign:hystrix:enabled : true# 在feign中开启hystrix功能,默认情况下feign不开启hystrix功能mybatis:configuration:map-underscore-to-camel-case: true

tx.properties 注意:必须添加,用来指定事务协调者的访问位置

# 默认之配置为TM的本机默认端口
tx-lcn.client.manager-address=127.0.0.1:8070

启动类 注意:启动类必须添加@EnableDistributedTransaction注解 启动分布式事务

package com.order;import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;/*** @author huangfu*/
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
@MapperScan("com.order.mapper")
@EnableDistributedTransaction
public class ServerOneApplication {public static void main(String[] args) {SpringApplication.run(ServerOneApplicatin.class);}
}

Mapper类 开发

package com.order.mapper;import com.pojo.ServerOne;
import org.apache.ibatis.annotations.Insert;/*** @author huangfu*/
public interface ServerOneMapper {/*** 插入数据* @param serverOne*/@Insert("insert into server1 values(#{id},#{name})")void insertData(ServerOne serverOne);
}

service类开发

package com.order.server;import com.pojo.ServerOne;/*** @author huangfu*/
public interface ServerOneService {/*** 插入数据* @param serverOne*/void insertData(ServerOne serverOne,String id);
}

注意:涉及到分布式事务的一定要添加 @LcnTransaction 注解

package com.order.server.impl;import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.order.client.ServerTwoClient;
import com.order.mapper.ServerOneMapper;
import com.order.server.ServerOneService;
import com.pojo.ServerOne;
import com.pojo.ServerTwo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** @author huangfu*/
@Service
@SuppressWarnings("all")
public class ServerOneServiceImpl implements ServerOneService {@Autowiredprivate ServerOneMapper serverOneMapper;@Autowiredprivate ServerTwoClient serverTwoClient;@Override@LcnTransaction@Transactional(rollbackFor = Exception.class)public void insertData(ServerOne serverOne,String id) {serverOneMapper.insertData(serverOne);ServerTwo serverTwo = new ServerTwo(serverOne.getId(),serverOne.getName());serverTwoClient.addData2(serverTwo);if("1".equals(id)){throw new RuntimeException("自定义异常");}System.out.println("---------------服务一执行完成---------------");}
}

feign远程调用Server2服务

package com.order.client;import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.pojo.ServerTwo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;/*** @author huangfu*/
@FeignClient(value = "server2")
public interface ServerTwoClient {@RequestMapping(value = "/addData2",method = RequestMethod.POST)public void addData2(@RequestBody ServerTwo serverTwo);
}
package com.order.client.impl;import com.order.client.ServerTwoClient;
import com.pojo.ServerTwo;
import org.springframework.stereotype.Component;/*** @author huangfu*/
@Component
public class ServerTwoClientImpl implements ServerTwoClient {@Overridepublic void addData2(ServerTwo serverTwo) {System.out.println("------断路器-------------");}
}

开发Controller

package com.order.controller;import com.order.server.ServerOneService;
import com.pojo.ServerOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.UUID;/*** @author huangfu*/
@RestController
public class ServerOneController {private final ServerOneService serverOneService;@Autowiredpublic ServerOneController(ServerOneService serverOneService) {this.serverOneService = serverOneService;}@RequestMapping("addDataOne")public String addDataOne(String id){ServerOne serverOne = new ServerOne();serverOne.setId(UUID.randomUUID().toString());serverOne.setName("张三");serverOneService.insertData(serverOne,id);return "success";}
}

项目结构

六、Server2开发

配置文件 appplication.yml

server:port: 8080spring:application:name: server2main:allow-bean-definition-overriding: truedatasource:driver-class-name:  com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/lcn-server2?useUnicode=true&characterEncoding=utf8username: rootpassword: rooteureka:client:service-url:defaultZone: http://localhost:8761/eureka/instance:prefer-ip-address: truefeign:hystrix:enabled : true# 在feign中开启hystrix功能,默认情况下feign不开启hystrix功能mybatis:configuration:map-underscore-to-camel-case: true

tx.properties 注意:必须添加,用来指定事务协调者的访问位置

# 默认之配置为TM的本机默认端口
tx-lcn.client.manager-address=127.0.0.1:8070

启动类 注意:启动类必须添加@EnableDistributedTransaction注解 启动分布式事务

package com.server2;import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;/*** @author huangfu*/
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
@MapperScan("com.server2.mapper")
@EnableDistributedTransaction
public class ServerTwoApplication {public static void main(String[] args) {SpringApplication.run(ServerTwoApplication.class);}
}

mapper

package com.server2.mapper;import com.pojo.ServerOne;
import com.pojo.ServerTwo;
import org.apache.ibatis.annotations.Insert;/*** @author huangfu*/
public interface ServerTwoMapper {/*** 插入数据* @param serverTwo*/@Insert("insert into server2 values(#{id},#{name})")void insertData(ServerTwo serverTwo);
}

service类开发

package com.server2.server;import com.pojo.ServerOne;
import com.pojo.ServerTwo;/*** @author huangfu*/
public interface ServerTwoService {/*** 插入数据* @param serverTwo*/void insertData(ServerTwo serverTwo);
}

注意:涉及到分布式事务的一定要添加 @LcnTransaction 注解

package com.server2.server.impl;import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.pojo.ServerOne;
import com.pojo.ServerTwo;
import com.server2.mapper.ServerTwoMapper;
import com.server2.server.ServerTwoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** @author huangfu*/
@Service
@SuppressWarnings("all")
public class ServerTwoServiceImpl implements ServerTwoService {@Autowiredprivate ServerTwoMapper serverTwoMapper;@Override@LcnTransaction@Transactional(rollbackFor = Exception.class)public void insertData(ServerTwo serverTwo) {serverTwoMapper.insertData(serverTwo);System.out.println("---------------服务二执行完成---------------");}}

Controller开发

package com.server2.controller;import com.pojo.ServerTwo;
import com.server2.server.ServerTwoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author huangfu*/
@RestController
public class ServerTwoController {@Autowiredprivate ServerTwoService serverTwoService;@PostMapping("addData2")public void addData(@RequestBody ServerTwo serverTwo){serverTwoService.insertData(serverTwo);}
}

server2项目结构

七、浏览器访问

http://localhost:8080/addDataOne?id=2 当id=1时出现异常,测试各数据库是否回滚

八、整体项目结构

TX-LCN分布式事务使用方案相关推荐

  1. LCN分布式事务框架实战

    本文来写个LCN分布式事务框架实战例子 文章目录 概述 概述 lcn分布式事务教程https://www.codingapi.com/docs/txlcn-preface/

  2. SpringCloud(7) LCN分布式事务框架入门

    官网:http://www.txlcn.org/ LCN原理:https://github.com/codingapi/tx-lcn/wiki/LCN%E5%8E%9F%E7%90%86 入门测试: ...

  3. SpringCloud - LCN分布式事务框架

    官网:http://www.txlcn.org/ LCN原理:https://github.com/codingapi/tx-lcn/wiki/LCN%E5%8E%9F%E7%90%86 入门测试: ...

  4. LCN分布式事务框架解决分布式事务一致性问题

    LCN分布式事务框架 框架介绍 LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果. 核心步骤 创建事务组 是指在事务发起方开始执行业务代码之前先调用TxMana ...

  5. 分布式事务实施方案总结

    一.术语介绍 TX协议:应用或者应用服务器与事务管理器的接口 XA协议:全局事务管理器与资源管理器的接口. 两阶段提交协议(Two-phase Commit,2PC) BASE理论:BA指的是基本业务 ...

  6. LCN分布式事务学习0-分布式事务理论基础

    1. 事务概述 1.1 事务的定义 将一个活动涉及到的所有操作纳入到一个不可分割的执行单元,只要其中任一操作执行失败,都将导致整个执行单元回滚. 简单地说,事务提供一种"要么什么都不做,要么 ...

  7. LCN分布式事务框架

    1.LCN是什么 LCN是国产开源的分布式事务处理框架.LCN即:lock(锁定事务单元).confirm(确认事务模块状态).notify(通知事务). 官网:http://www.txlcn.or ...

  8. LCN 分布式事务框架

    1.LCN 框架的由来 在设计框架之初的1.0 ~ 2.0的版本时,框架设计的步骤是如下的,各取其首字母得来的LCN命名: 锁定事务单元(lock) 确认事务模块状态(confirm) 通知事务( n ...

  9. 分布式事务(二)LCN分布式事务框架

    1. 简介 LCN框架在2017年6月发布第一个版本,目前最新已经达到5.0版本. LCN早期设计时,1.0版本和2.0版本设计步骤如下: 锁定事务单元(Lock) 确认事务模块状态(Confirm) ...

最新文章

  1. 涨见识了,在终端执行 Python 代码的 6 种方式
  2. NSNotification消息通知实现源码(观察者模式原理)
  3. 我对STL的一些看法(一)初步认识STL
  4. java第二章_JAVA第二章知识点
  5. 基因组中的趣事(二)- 最长的基因2.7 million,最短的基因只有8 nt却能编码
  6. pytorch torch.optim.Optimizer
  7. WebApi接口访问异常问题。尝试创建“testController”类型的控制器时出错。请确保控制器具有无参数公共构造函数
  8. 腾讯云与同方全球人寿签署战略合作 “云+保险”合作伙伴队伍再壮大
  9. 利用R语言的GWmodel进行GWR模型分析(内含错误解决方法)
  10. 用html写QQ邮箱注册页面,制作简易QQ邮箱登录页面
  11. 无线键鼠接收器配对怎么就那么难?简直就是浪费
  12. 文件名太长无法删除怎么办
  13. 从零开始 verilog 以太网交换机(一)架构分析
  14. Android 亮度调节
  15. 我的世界服务器显示披风指令,我的世界电脑披风指令 | 手游网游页游攻略大全...
  16. Chrome浏览器默认打开无痕模式
  17. html 源码_HTML实例之搜索栏(附源码)
  18. 实测一种动态再平衡投资策略
  19. 计算机网络:Email 协议 (SMTP、POP3、IMAP)
  20. 林子雨—大数据技术原理与应用—上机实验二

热门文章

  1. 数据堂公司董事长齐红威应邀参加安徽省政府组织的企业家恳谈会
  2. 计算机学科专业基础综合803,803计算机学科基础综合
  3. 红海已现 透视2014国内公有云市场
  4. 论题:基于机器学习的垃圾邮件过滤系统
  5. 英语信函范文之介绍信
  6. 实现高德坐标转GPS坐标
  7. 【Python】判断文件类型(格式)
  8. UA PHYS515A 电磁理论IV 时变电磁场理论5 电磁场的角动量
  9. t3怎么设置远程服务器,T1怎么配置才能让客户端远程登录上服务器呢?不借助任何第三方工具。...
  10. 科技的发展让隐私保护成空谈