分布式事务处理技术之LCN原理

第一章 分布式事务介绍

一、什么是分布式事务

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

举个栗子
电商系统中的订单系统与库存系统
在这里插入图片描述
图中包含了库存和订单两个独立的微服务,每个微服务维护了自己的数据库。
在交易系统的业务逻辑中,一个商品在下单之前需要先调用库存服务,进行扣除库存,再调用订单服务,创建订单记录。

在这里插入图片描述
正常情况下,两个数据库各自更新成功,两边数据维持着一致性。如果在非正常情况下,有可能库存的扣减完成了,随后的订单记录却因为某些原因插入失败。或者是订单创建成功了,但是库存扣除商品的数据量失败了,这个时候,两边数据就失去了应有的一致性

在这里插入图片描述
这时候我们需要保证分布式事务的一致性,单数据源的用单机事务来保证。多数据源就需要依赖分布式事务来处理。

二、XA 的两阶段提交方案

  1. 什么是XA 协议

    XA 协议由Oracle Tuxedo 首先提出的,并交给X/Open 组织,作为资源管理器(数据库)与事务管理器的接口标准。目前,Oracle、Informix、DB2 和Sybase 等各大数据库厂家都提供对XA 的支持。XA 协议采用两阶段提交方式来管理分布式事务。XA 接口提供资源管理器与事务管理器之间进行通信的标准接口。

    XA 就是X/Open DTP 定义的交易中间件与数据库之间的接口规范(即接口函数),交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA 接口函数由数据库厂商提供。

    X/Open 组织(即现在的Open Group)定义了分布式事务处理模型。X/Open DTP 模型(1994)包括:
    应用程序(AP)、
    事务管理器(TM)、
    资源管理器(RM)、
    通信资源管理器(CRM)。

    一般常见的事务管理器(TM)是交易中间件,常见的资源管理器(RM)是数据库,常见的通信资源管理器(CRM)是消息中间件。

  2. XA 协议的一阶段提交

    一阶段提交协议相对简单。优点也很直观,它不用再与其他的对象交互,节省了判断步骤和时间,所以在性能上是在阶段提交协议中最好的。
    但缺点也很明显:数据库确认执行事务的时间较长,出问题的可能性就随之增大。如果有多个数据源,一阶段提交协议无法协调他们之间的关系。

    在这里插入图片描述

    如果在程序中开启了事务,那么在应用程序发出提交/回滚请求后,数据库执行操作,而后将成功/失败返回给应用程序,程序继续执行。

  3. XA 协议的二阶段提交

    二阶段三角色: 在一阶段协议的基础上,有了二阶段协议,二阶段协议的好处是添加了一个管理者角色。

    在这里插入图片描述

    很明显,二阶段协议通过将两层变为三层,增加了中间的管理者角色,从而协调多个数据源之间的关系,二阶段提交协议分为两个阶段。

    在这里插入图片描述

    应用程序调用了事务管理器的提交方法,此后第一阶段分为两个步骤:
    事务管理器通知参与该事务的各个资源管理器,通知他们开始准备事务。
    资源管理器接收到消息后开始准备阶段,写好事务日志并执行事务,但不提交,
    然后将是否就绪的消息返回给事务管理器(此时已经将事务的大部分事情做完,以后的内容耗时极小)。

    在这里插入图片描述
    第二阶段也分为两个步骤:
    a. 事务管理器在接受各个消息后,开始分析,如果有任意其一失败,则发送回滚命令,否则发送提交命令
    b. 各个资源管理器接收到命令后,执行(耗时很少),并将提交消息返回给事务管理器
    事务管理器接受消息后,事务结束,应用程序继续执行。

    为什么要分两步执行?

    一是因为分两步,就有了事务管理器统一管理的机会;
    二是尽可能晚地提交事务,让事务在提交前尽可能地完成所有能完成的工作,
    这样,最后的提交阶段将是耗时极短,耗时极短意味着操作失败的可能性也就降低。
    同时,二阶段提交协议为了保证事务的一致性,不管是事务管理器还是各个资源管理器,
    每执行一步操作,都会记录日志,为出现故障后的恢复准备依据。

    缺点:

    1 二阶段提交协议的存在的弊端是阻塞,因为事务管理器要收集各个资源管理器的响应消息,
    如果其中一个或多个一直不返回消息,则事务管理器一直等待,应用程序也被阻塞,甚至可能永久阻塞。
    2 两阶段提交理论的一个广泛工业应用是XA 协议。目前几乎所有收费的商业数据库都支持XA 协议。
    XA 协议已在业界成熟运行数十年,但目前它在互联网海量流量的应用场景中,吞吐量这个瓶颈变得十分致命,因此很少被用到。

三、TCC 解决方案

  1. TCC 介绍
    TCC 是由支付宝架构师提供的一种柔性解决分布式事务解决方案,主要包括三个步骤
    Try:预留业务资源/数据效验
    Confirm:确认执行业务操作
    Cancel:取消执行业务操作

    在这里插入图片描述
    幂等性: 在进行事务提交时 ,将多次操作合并成为一次并提交

  2. TCC 原理
    TCC 方案在电商、金融领域落地较多。TCC 方案其实是两阶段提交的一种改进。
    其将整个业务逻辑的每个分支显式的分成了Try、Confirm、Cancel 三个操作.
    Try 部分完成业务的准备工作,confirm 部分完成业务的提交,cancel 部分完成事务的回滚。
    基本原理如下图所示。

    在这里插入图片描述

    事务开始时,业务应用会向事务协调器注册启动事务。
    之后业务应用会调用所有服务的try 接口,完成一阶段准备。
    之后事务协调器会根据try 接口返回情况,决定调用confirm接口或者cancel 接口。
    如果接口调用失败,会进行重试。微服务倡导服务的轻量化、易部署,
    而TCC 方案中很多事务的处理逻辑需要应用自己编码实现,复杂且开发量大

  3. TCC 的关键流程如下图(以创建订单和扣减库存为例子)

在这里插入图片描述

  1. TCC 优缺点

    优点
    让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。

    缺点

    对应用的侵入性强。业务逻辑的每个分支都需要实现try、confirm、cancel三个操作,
    应用侵入性较强,改造成本高。实现难度较大。
    需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。
    为了满足一致性的要求,confirm 和cancel 接口必须实现幂等。

四、分布式事务中间件解决方案

分布式事务中间件其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果
典型代表有:阿里的GTS(https://www.aliyun.com/aliware/txc)、开源应用LCN
其实现原理如下:

在这里插入图片描述

第二章 LCN分布式事务处理框架介绍

一、什么是LCN 框架

  1. LCN 框架的由来
    在设计框架之初的1.0 ~ 2.0 的版本时,框架设计的步骤是如下的,各取其首字母得来的LCN 命名。
    LCN: 锁定事务单元(lock)、确认事务模块状态(confirm)、通知事务(notify)
    它的宗旨 : LCN 并不生产事务,LCN 只是本地事务的协调工

  2. LCN 框架相关资料( 学习还是得靠自己钻研呀~~~ )
    tx-lcn 官方地址:https://www.txlcn.org/
    tx-lcn Github 地址:https://github.com/codingapi/tx-lcn
    tx-lcn 服务下载地址:https://pan.baidu.com/s/1cLKAeE#list/path=%2F
    tx-lcn 服务源码地址:https://github.com/codingapi/tx-lcn/tree/master/tx-manager

二、LCN 框架原理及执行步骤

  1. LCN 的执行原理
    在这里插入图片描述

    在上图中,微服务A,微服务B,TxManager 事务协调器,都需要去Eureka 中注册服务。
    Eureka 是用于TxManager 与其他服务之间的相互服务发现。
    redis 是用于存放我们事务组的信息以及补偿的信息。

    然后微服务A 与微服务B 他们都需要去配置上我们TxClient 的包架构(代码的包架构);
    来支持我们的LCN 框架,以及他们的数据库。

  2. LCN 执行步骤

    创建事务组
    事务组是指的我们在整个事务过程中把各个节点(微服务)单元的事务信息存储在一个固定单元里。
    但这个信息并不是代表是事务信息,而是只是作为一个模块的标示信息。
    创建事务组是指在事务发起方开始执行业务代码之前先调用TxManager 创建事务组对象,
    然后拿到事务标示GroupId 的过程。

    添加事务组
    添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息添加通知给TxManager 的操作。

    关闭事务组
    是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager 的动作。
    当执行完关闭事务组的方法以后,TxManager 将根据事务组信息来通知相应的参与模块提交或回滚事务。

  3. 业务执行流程图
    在这里插入图片描述

三、什么是LCN 的事务协调机制

在这里插入图片描述

如图:
假设服务已经执行到关闭事务组的过程,那么接下来作为一个模块执行通知给TxManager,
然后告诉他本次事务已经完成。那么如图中Txmanager 下一个动作就是通过事务组的id,
获取到本次事务组的事务信息;然后查看一下对应有那几个模块参与,
如果是有A/B/C 三个模块;那么对应的对三个模块做通知、提交、回滚。

那么提交的时候是提交给谁呢?
是提交给了我们的TxClient 模块。然后TxCliient 模块下有一个连接池,就是框架自定义的一个连接池(如图DB 连接池);这个连接池其实就是在没有通知事务之前一直占有着这次事务的连接资源,就是没有释放。
但是他在切面里面执行了close 方法。在执行close的时候。
如果需要(TxManager)分布式事务框架的连接。他被叫做“假关闭”,也就是没有关闭,
只是在执行了一次关闭方法。实际的资源是没有释放的。这个资源是掌握在LCN 的连接池里的。

当TxManager 通知提交或事务回滚的时候呢?
TxManager 会通知我们的TxClient 端。然后TxClient 会去执行相应的提交或回滚。
提交或回滚之后再去关闭连接。这就是LCN 的事务协调机制。
说白了就是代理DataSource 的机制;相当于是拦截了一下连接池,控制了连接池的事务提交。

四、LCN 的事务补偿机制

  1. 什么是补偿事务机制?
    LCN 的补偿事务原理是模拟上次失败事务的请求,然后传递给TxClient 模块然后再次执行该次请求事务
    简单的说:lcn 事务补偿是指在服务挂机和网络抖动情况下txManager 无法通知事务单元时。(通知不到也就两种原因服务挂了和网络出问题)在这种情况下TxManager 会做一个标示;然后返回给发起方。
    告诉他本次事务有存在没有通知到的情况。那么如果是接收到这个信息之后,发起方就会做一个标示,
    标示本次事务是需要补偿事务的。这就是事务补偿机制。

  2. 为什么需要事务补偿?
    事务补偿是指在执行某个业务方法时,本应该执行成功的操作却因为服务器挂机或者网络抖动等问题
    导致事务没有正常提交
    ,此种场景就需要通过补偿来完成事务,从而达到事务的一致性。

  3. 补偿机制的触发条件?
    当执行关闭事务组步骤时,若发起方接受到失败的状态后将会把该次事务识别为待补偿事务
    然后发起方将该次事务数据异步通知给TxManager。TxManager 接受到补偿事务以后
    先通知补偿回调地址,然后再根据是否开启自动补偿事务状态来补偿或保存该次切面事务数据。

第三章 LCN分布式事务框架应用

一、LCN 分布式事务框架应用

  1. 需求
    创建两个服务接口项目 springcloud-order-service,springcloud-inventory-servicec
    创建三个服务分别为:springcloud-portal、springcloud-order、springcloud-inventory。
    在springcloud-portal 服务中处理创建订单的请求,
    然后分别请求springcloud-order 以及springcloud-inventory 服务。令其调用对应的接口项目
    在springcloud-order 中插入一条订单数据,在springcloud-inventory中对商品的数量做更新。

  2. 使用技术
    数据库:Mysql
    开发平台:SpringCloud+SpringBoot+MyBatis

  3. 数据库设计
    创建两个数据库分别为:chy_orders,chy_inventory。
    springcloud-order 操作 chy_orders 库,springclooud-inventory 操作 chy_inventory 库

    a. 在 chy_orders 库中包含一个tb_orders 表。表结构如下:

    CREATE TABLE `tb_orders` (
    `orderid` int(11) NOT NULL AUTO_INCREMENT,
    `itemid` int(11) DEFAULT NULL,
    `price` int(11) DEFAULT NULL,
    PRIMARY KEY (`orderid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
         
         
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    b.在 chy_inventory 库中包含一个tb_inventory 表。表结构如下:

    CREATE TABLE `tb_inventory` (
    `inventoryid` int(11) NOT NULL AUTO_INCREMENT,
    `itemid` int(11) DEFAULT NULL,
    `itemnum` int(11) DEFAULT NULL,
    PRIMARY KEY (`inventoryid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
         
         
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

环境搭建

项目结构
在这里插入图片描述

创建入口项目 springcloud-portal
  1. 通过官网快速构建项目 web启动器,Eureka客户端,feign

    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.1.8.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    	<properties>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
    	</properties>
    	<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>
    	</dependencies>
    
         
         
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  2. 修改配置文件 application.yml(效果同application.properties)

    spring:
    	  application:
    	    name: springcloud-portal
    
    <span class="token key atrule">server</span><span class="token punctuation">:</span>
      <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">8080</span>
      
    
    <span class="token key atrule">eureka</span><span class="token punctuation">:</span>
      <span class="token key atrule">client</span><span class="token punctuation">:</span>
        <span class="token key atrule">serviceUrl</span><span class="token punctuation">:</span>
          <span class="token key atrule">defaultZone</span><span class="token punctuation">:</span> http<span class="token punctuation">:</span>//admin<span class="token punctuation">:</span>admin@eureka1<span class="token punctuation">:</span>8761/eureka/<span class="token punctuation">,</span>http<span class="token punctuation">:</span>//admin<span class="token punctuation">:</span>admin@eureka2<span class="token punctuation">:</span>8761/eureka/
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 启动类

    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients
    public class Application {
    
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	SpringApplication<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>Application<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    创建接口项目springcloud-order-service ,springcloud-inventory-service
    1. 通过官网快速构建,添加web启动器,pom文件除项目名外一样

      	<parent>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-parent</artifactId>
      		<version>2.1.8.RELEASE</version>
      		<relativePath /> <!-- lookup parent from repository -->
      	</parent>
      
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>properties</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>java.version</span><span class="token punctuation">&gt;</span></span>1.8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>java.version</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>spring-cloud.version</span><span class="token punctuation">&gt;</span></span>Greenwich.SR3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>spring-cloud.version</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>maven-jar-plugin.version</span><span class="token punctuation">&gt;</span></span>2.6<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>maven-jar-plugin.version</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>properties</span><span class="token punctuation">&gt;</span></span>
      
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencies</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-web<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencies</span><span class="token punctuation">&gt;</span></span>
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    创建接口实现项目(类似生产者)springcloud-order, springcloud-inventory
    1. 快速构建SpringBoot项目,修改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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      	<modelVersion>4.0.0</modelVersion>
      	<parent>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-parent</artifactId>
      		<version>2.1.8.RELEASE</version>
      		<relativePath/> <!-- lookup parent from repository -->
      	</parent>
      	<groupId>ah.szxy.lcn</groupId>
      	<artifactId>springcloud-order</artifactId>
      	<version>0.0.1-SNAPSHOT</version>
      	<name>springcloud-portal</name>
      	<description>SpringLCN Project</description>
      
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>properties</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>java.version</span><span class="token punctuation">&gt;</span></span>1.8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>java.version</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>spring-cloud.version</span><span class="token punctuation">&gt;</span></span>Greenwich.SR3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>spring-cloud.version</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>maven-jar-plugin.version</span><span class="token punctuation">&gt;</span></span>2.6<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>maven-jar-plugin.version</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>properties</span><span class="token punctuation">&gt;</span></span>
      
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencies</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-web<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.cloud<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-cloud-starter-netflix-eureka-client<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.cloud<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-cloud-starter-openfeign<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      	
      	<span class="token comment">&lt;!-- Mybatis启动器 --&gt;</span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.mybatis.spring.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>mybatis-spring-boot-starter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>1.1.1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      	<span class="token comment">&lt;!-- mysql数据库驱动 --&gt;</span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>mysql<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>mysql-connector-java<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      	<span class="token comment">&lt;!-- druid数据库连接池 --&gt;</span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.alibaba<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>druid<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>1.0.9<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      
      	<span class="token comment">&lt;!-- 添加相关依赖接口项目的坐标,以便能使使用其抽象方法和实体类 --&gt;</span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>an.szxy.lcn<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>springcloud-order-service<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>0.0.1-SNAPSHOT<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencies</span><span class="token punctuation">&gt;</span></span>
      
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencyManagement</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencies</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
      			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.cloud<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-cloud-dependencies<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>${spring-cloud.version}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
      			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>type</span><span class="token punctuation">&gt;</span></span>pom<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>type</span><span class="token punctuation">&gt;</span></span>
      			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>import<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencies</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencyManagement</span><span class="token punctuation">&gt;</span></span>
      
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>build</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plugins</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plugin</span><span class="token punctuation">&gt;</span></span>
      			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
      			<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-maven-plugin<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
      		<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plugin</span><span class="token punctuation">&gt;</span></span>
      	<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plugins</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>build</span><span class="token punctuation">&gt;</span></span>
      

    </project>

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    注意:
    1.添加web启动器,Eureka客户端,声明式调用feign ,mybatis启动器,mysql数据库驱动,数据库连接池
    2.添加相关依赖接口项目的坐标,以便能使使用其抽象方法和实体类

  • 修改全局配置文件 application.yml
    修改应用名,数据库链接参数,mybatis的别名配置,Eureka注册中心/集群的配置

    spring:       #配置应用名,数据库连接参数
      application:
        name: springcloud-order
      datasource:
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/chy_orders?useUnicode=true&characterEncoding=gbk&useJDBCCompliantTimezoneShift=true&serverTimezone=UTC
        username: root
        password: root
        type: com.alibaba.druid.pool.DruidDataSource
    
  • server: #配置端口号
    port: 8081

    mybatis: #指定POJO扫描包来让mybatis自动扫描到自定义POJO
    type-aliases-package: ah.szxy.pojo

    eureka: #配置Eureka服务注册中心地址
    client:
    serviceUrl:
    defaultZone: http://admin:admin@eureka1:8761/eureka/,http://admin:admin@eureka2:8761/eureka/

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 启动类
    完全一样,只要包名一致的话

    @SpringBootApplication
    @EnableEurekaClient
    @MapperScan("ah.szxy.mapper")
    public class Application {
    
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	SpringApplication<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>Application<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    实现业务

    实现添加订单业务
    1. 接口项目中添加接口类
      注意: 使用POST方法提交整合对象需要使用RequestBody 注解

      public interface OrderServiceAPI {
      
      <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>value<span class="token operator">=</span><span class="token string">"addOrder"</span><span class="token punctuation">,</span>method<span class="token operator">=</span>RequestMethod<span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
      <span class="token keyword">void</span> <span class="token function">addOrder</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> Orders orders<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//post传递一个对象,使用@RequestBody</span>
      

    }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 在业务接口项目中添加pojo

    public class Orders implements Serializable{
    	private Integer orderid;
    	private Integer itemid;
    	private Integer price;
    	public Integer getOrderid() {
    		return orderid;
    	}
    	public void setOrderid(Integer orderid) {
    		this.orderid = orderid;
    	}
    	public Integer getItemid() {
    		return itemid;
    	}
    	public void setItemid(Integer itemid) {
    		this.itemid = itemid;
    	}
    	public Integer getPrice() {
    		return price;
    	}
    	public void setPrice(Integer price) {
    		this.price = price;
    	}
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 添加mapper(业务层接口项目)
    OrdersMapper .java

    public interface OrdersMapper {
    	void insertOrder(Orders orders);
    }
    
    • 1
    • 2
    • 3
    • 4

    OrdersMapper .xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="ah.szxy.mapper.OrdersMapper">
    
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>insert</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>insertOrder<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    	insert into tb_orders(itemid,price) values(#{itemid},#{price})
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>insert</span><span class="token punctuation">&gt;</span></span>
    

    </mapper>

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 添加业务层(手动开启事务注解)

    public interface OrdersService {
    	void inserOrders(Orders orders);
    }
    
  • @Service
    public class OrdersServiceImpl implements OrdersService {

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> OrdersMapper ordersMapper<span class="token punctuation">;</span>
    
    <span class="token annotation punctuation">@Override</span>
    <span class="token annotation punctuation">@Transactional</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">inserOrders</span><span class="token punctuation">(</span>Orders orders<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>ordersMapper<span class="token punctuation">.</span><span class="token function">insertOrder</span><span class="token punctuation">(</span>orders<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    

    }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 添加controller
    思考为什么要使用RestController注解?

    @RestController
    public class OrdersController implements OrderServiceAPI{
    	@Autowired
    	private OrdersService ordersService;
    
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addOrder</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> Orders orders<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>ordersService<span class="token punctuation">.</span><span class="token function">inserOrders</span><span class="token punctuation">(</span>orders<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    实现修改库存商品数量业务
    1. 接口项目添加接口

      public interface InventoryServiceAPI {
      
      <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>value<span class="token operator">=</span><span class="token string">"updateInventory"</span><span class="token punctuation">,</span>method<span class="token operator">=</span>RequestMethod<span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
      <span class="token keyword">void</span> <span class="token function">updateInventory</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> Inventory inventory<span class="token punctuation">)</span><span class="token punctuation">;</span> 
      

    }

    • 1
    • 2
    • 3
    • 4
    • 5
  • 在业务接口项目中添加pojo

    public class Inventory implements Serializable{
    
    <span class="token keyword">private</span> Integer inventoryid<span class="token punctuation">;</span>
    <span class="token keyword">private</span> Integer itemid<span class="token punctuation">;</span>
    <span class="token keyword">private</span> Integer itemnum<span class="token punctuation">;</span>
    <span class="token keyword">public</span> Integer <span class="token function">getInventoryid</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">return</span> inventoryid<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setInventoryid</span><span class="token punctuation">(</span>Integer inventoryid<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>inventoryid <span class="token operator">=</span> inventoryid<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">public</span> Integer <span class="token function">getItemid</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">return</span> itemid<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setItemid</span><span class="token punctuation">(</span>Integer itemid<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>itemid <span class="token operator">=</span> itemid<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">public</span> Integer <span class="token function">getItemnum</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">return</span> itemnum<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setItemnum</span><span class="token punctuation">(</span>Integer itemnum<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>itemnum <span class="token operator">=</span> itemnum<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 添加mapper

    public interface InventoryMapper {
    	void updateInventory(Inventory inventory);
    }
    
    • 1
    • 2
    • 3
    • 4
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="ah.szxy.mapper.InventoryMapper">
    
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>update</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>updateInventory<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
    	update tb_inventory set itemnum=#{itemnum} where itemid=#{itemid}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>update</span><span class="token punctuation">&gt;</span></span>
    

    </mapper>

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 添加业务层 (手动添加事务注解)

    public interface InventoryService {
    	 void updateInventory(Inventory inventory);
    }
    
  • @Service
    public class InventoryServiceImpl implements InventoryService {

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> InventoryMapper inventoryMapper<span class="token punctuation">;</span>
    
    <span class="token annotation punctuation">@Override</span>
    <span class="token annotation punctuation">@Transactional</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">updateInventory</span><span class="token punctuation">(</span>Inventory inventory<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>inventoryMapper<span class="token punctuation">.</span><span class="token function">updateInventory</span><span class="token punctuation">(</span>inventory<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    

    }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 添加controller

    @RestController
    public class InventoryController implements InventoryServiceAPI {
    
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> InventoryService inventoryService<span class="token punctuation">;</span>
    
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">updateInventory</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> Inventory inventory<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>inventoryService<span class="token punctuation">.</span><span class="token function">updateInventory</span><span class="token punctuation">(</span>inventory<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    实现portal 中的创建订单业务
    1. 添加实现服务接口的接口
      注意:继承的是接口项目的接口类, 但Feign调用的确实他们的业务实现项目

      package ah.szxy.feign.service;
      

    import org.springframework.cloud.openfeign.FeignClient;

    import ah.szxy.service.InventoryServiceAPI;

    @FeignClient(“springclooud-inventory”)
    public interface Portal_Inventory_service extends InventoryServiceAPI {

    }

    package ah.szxy.feign.service;

    import org.springframework.cloud.openfeign.FeignClient;

    import ah.szxy.service.OrderServiceAPI;

    @FeignClient(“springcloud-order”)
    public interface Portal_Orders_Service extends OrderServiceAPI{

    }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 添加portalService 接口

    public interface PortalService {
    	void addOrder();
    }
    
  • @Service
    public class PortalServiceImpl implements PortalService{
    @Autowired
    private Portal_Orders_Service orderService;
    @Autowired
    private Portal_Inventory_service inventoryService;

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addOrder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	Orders orders <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Orders</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	orders<span class="token punctuation">.</span><span class="token function">setItemid</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	orders<span class="token punctuation">.</span><span class="token function">setPrice</span><span class="token punctuation">(</span><span class="token number">666</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	
    	Inventory inventory <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Inventory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	inventory<span class="token punctuation">.</span><span class="token function">setItemid</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	inventory<span class="token punctuation">.</span><span class="token function">setItemnum</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	
    	<span class="token keyword">this</span><span class="token punctuation">.</span>orderService<span class="token punctuation">.</span><span class="token function">addOrder</span><span class="token punctuation">(</span>orders<span class="token punctuation">)</span><span class="token punctuation">;</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>inventoryService<span class="token punctuation">.</span><span class="token function">updateInventory</span><span class="token punctuation">(</span>inventory<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    

    }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
  • 添加controller

    @RestController
    public class PortalController {
    
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> PortalService portalService<span class="token punctuation">;</span>
    
    <span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"add"</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> Map<span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">,</span>String<span class="token punctuation">&gt;</span></span><span class="token function">addOrder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    	<span class="token keyword">this</span><span class="token punctuation">.</span>portalService<span class="token punctuation">.</span><span class="token function">addOrder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	Map<span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">,</span> String<span class="token punctuation">&gt;</span></span>map<span class="token operator">=</span><span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">,</span> String<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"msg"</span><span class="token punctuation">,</span> <span class="token string">"ok"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    	
    	
    	<span class="token keyword">return</span> map<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 添加启动类
    使用了feign的注解,所以需要添加@EnableFeignClients

    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients
    public class Application {
    
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	SpringApplication<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>Application<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试

    1. 在数据库中插入一条出库数据
      在这里插入图片描述
      2.访问入口项目的controller,可以看到访问成功
      在这里插入图片描述
      3.查看数据库,可以看到生成了订单的数据

      在这里插入图片描述
      而且,库存的订单数量由10改为了6 ,由结果来看我们似乎模拟成功了在这里插入图片描述

    小结:

    如果我们使一个事务的操作出现问题时,例如将添加订单的sql语句故意写错时,
    虽然我们手动添加了@Transaction注解,但是我们重新运行项目时,
    可以看到订单虽然没有被添加但是库存却可以被修改
    因此我们需要明白的是,这个项目只是模拟了没有使用LCN ,即没有使用分布式事务管理的情况,
    下面我们将会逐渐引入LCN来让我们理解他的强大之处!!!

    使用LCN 实现分布式事务处理_服务端

    1. 下载LCN 事务协调器(使用的版本为5.0.2)

      https://codeload.github.com/codingapi/tx-lcn/zip/5.0.2.RELEASE

    2. 使用eclipse以Maven的形式导入该源码

    在这里插入图片描述

    1. 解压并将整个项目 tx-lcn-5.02.RELEASE 导入到eclipse
      问题:
      导入后, 源码中大量的log无法通过@Slf4j注解找到log变量,
      而且大量的set/get方法注解也都失效了。
      解决:

      a.下载lombok.jar : https://projectlombok.org/download.html
      b.将 lombok.jar 复制到 myeclipse.ini 所在的文件夹目录下
      c.双击lomok.jar开始安装
      d.重启 myeclipse

      注意:如果是安装在C盘,则在安装的时候提示需要管理员权限 ,如下图
      需要我们根据提示,使用管理员权限运行CMD窗口,
      然后跳转到lomock所在目录,运行该jar即可

      在这里插入图片描述

      在这里插入图片描述
      出现下面这个类似红辣椒的标志代表安装成功,重启myeclipse 即可
      在这里插入图片描述

    2. 找到tx-lcn下的 txlcn-tm,找到resource下的 .sql文件,在数据库中运行

      在这里插入图片描述
      注意: .sql文件中的代码如下 , 但首先应该创建 tx-manager 这个数据库

      /*
       Navicat Premium Data Transfer
      

    Source Server : local
    Source Server Type : MySQL
    Source Server Version : 100309
    Source Host : localhost:3306
    Source Schema : tx-manager

    Target Server Type : MySQL
    Target Server Version : 100309
    File Encoding : 65001

    Date: 29/12/2018 18:35:59
    */
    CREATE DATABASE IF NOT EXISTS </span>tx<span class="token operator">-</span>manager<span class="token punctuation"> DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
    USE </span>tx<span class="token operator">-</span>manager<span class="token punctuation">;

    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;

    – ----------------------------
    – Table structure for t_tx_exception
    – ----------------------------
    DROP TABLE IF EXISTS </span>t_tx_exception<span class="token punctuation">;
    CREATE TABLE </span>t_tx_exception<span class="token punctuation"> (
    </span>id<span class="token punctuation"> bigint(20) NOT NULL AUTO_INCREMENT,
    </span>group_id<span class="token punctuation"> varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    </span>unit_id<span class="token punctuation"> varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    </span>mod_id<span class="token punctuation"> varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    </span>transaction_state<span class="token punctuation"> tinyint(4) NULL DEFAULT NULL,
    </span>registrar<span class="token punctuation"> tinyint(4) NULL DEFAULT NULL,
    </span>ex_state<span class="token punctuation"> tinyint(4) NULL DEFAULT NULL COMMENT ‘0 待处理 1已处理’,
    </span>remark<span class="token punctuation"> varchar(10240) NULL DEFAULT NULL COMMENT ‘备注’,
    </span>create_time<span class="token punctuation"> datetime(0) NULL DEFAULT NULL,
    PRIMARY KEY (</span>id<span class="token punctuation">) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 967 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

    SET FOREIGN_KEY_CHECKS = 1;

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 修改配置文件 application.properties

    pring.application.name=TransactionManager
    server.port=7970
    
  • #数据库配置
    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=root
    spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
    spring.jpa.hibernate.ddl-auto=update

    #Redis的配置
    spring.redis.host=192.168.179.131
    spring.redis.port=6379
    spring.redis.password=

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    官方提供的详细的配置文件

    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
    注意(NOTE)
    (1) TxManager所有配置均有默认配置,请按需覆盖默认配置。
    (2) 特别注意 TxManager进程会监听两个端口号,一个为TxManager端口,另一个是事务消息端口。TxClient默认连接事务消息端口是8070, 所以,为保证TX-LCN基于默认配置运行良好,请设置TxManager端口号为8069 或者指定事务消息端口为8070
    (3) 分布式事务执行总时间 a 与 TxClient通讯最大等待时间 b、TxManager通讯最大等待时间 c、微服务间通讯时间 d、微服务调用链长度 e 几个时间存在着依赖关系。 a >= 2c + (b + c + d) * (e - 1), 特别地,b、c、d 一致时,a >= (3e-1)b。你也可以在此理论上适当在减小a的值,发生异常时能更快得到自动补偿,即 a >= (3e-1)b - Δ(原因)。 最后,调用链小于等于3时,将基于默认配置运行良好
    (4) 若用tx-lcn.manager.ex-url=/provider/email-to/xxx@xx.xxx 这个配置,配置管理员邮箱信息(如QQ邮箱):
    spring.mail.host=smtp.qq.com
    spring.mail.port=587
    spring.mail.username=xxxxx@
    *.com

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
  • 启动项目
    访问http://localhost:7970 ,初始密码为codingapi
    在配置文件中设置 tx-lcn.manager.admin-key=admin可修改密码为 admin

    效果如下
    在这里插入图片描述

  • 使用LCN 实现分布式事务处理_客户端

    1. 添加相关坐标

      <!-- 使用事务管理器TM所需要添加的坐标 -->
      		<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>
      
         
         
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    2. 在需要事务处理的方法上加入@LcnTransaction注解

      @Override
      	@LcnTransaction
      	public void addOrder() {
      		Orders orders = new Orders();
      		orders.setItemid(100);
      		orders.setPrice(666);
      
      	Inventory inventory <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Inventory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      	inventory<span class="token punctuation">.</span><span class="token function">setItemid</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      	inventory<span class="token punctuation">.</span><span class="token function">setItemnum</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      	
      	<span class="token keyword">this</span><span class="token punctuation">.</span>orderService<span class="token punctuation">.</span><span class="token function">addOrder</span><span class="token punctuation">(</span>orders<span class="token punctuation">)</span><span class="token punctuation">;</span>
      	<span class="token keyword">this</span><span class="token punctuation">.</span>inventoryService<span class="token punctuation">.</span><span class="token function">updateInventory</span><span class="token punctuation">(</span>inventory<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 在启动类中添加@EnableDistributedTransaction注解

    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients
    @EnableDistributedTransaction    //使用lcn时,需要添加
    public class Application {
    
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    	SpringApplication<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>Application<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
  • }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意:
    在使用lcn时,需要我们配置数据库连接池,也就需要我们配置数据库的链接参数,
    在配置这些东西同时也就需要我们添加mybatis的启动器,数据库连接池以及mysql-connector的坐标
    在本项目中,创建三个服务分别为:springcloud-portal、springcloud-order、springcloud-inventory都需要进行这五步操作

    a.mybatis的启动器,数据库连接池以及mysql-connector的坐标

    		<!-- Mybatis启动器 -->
    		<dependency>
    			<groupId>org.mybatis.spring.boot</groupId>
    			<artifactId>mybatis-spring-boot-starter</artifactId>
    			<version>1.1.1</version>
    		</dependency>
    		<!-- mysql数据库驱动 -->
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    		</dependency>
    		<!-- druid数据库连接池 -->
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>druid</artifactId>
    			<version>1.0.9</version>
    		</dependency>
    
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    b.数据库的链接参数

    spring:
      datasource:
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/chy_inventory?useUnicode=true&characterEncoding=gbk&useJDBCCompliantTimezoneShift=true&serverTimezone=UTC
        username: root
        password: root
        type: com.alibaba.druid.pool.DruidDataSource
    
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试效果

    部署完毕后,启动所有项目(包括 lcn-tm项目),
    首先访问 txlcn-tm(LCN服务端项目),发现下面三个项目都在运行

    在这里插入图片描述

    在这里插入图片描述

    这里是重中之重的测试

    紧接上次测试 , 上次将添加订单的sql语句故意写错时,
    然后运行portal入口项目时, 发现虽然运行报错, 订单表没有插入数据, 但是库存仍可被修改,
    现在数据库中,将订单表中的数据删除 ,将库存数据设置为初始值后,
    再次运行项目后 ,我们可以看到 ,项目运行同样出错,
    然是不同的是 , 订单表没有插入数据 ,同时库存表也是初始值 ,
    同时证明了LCN对分布式事务的协调是成功的

    附1: 错误页面

    在这里插入图片描述

    附2: 订单表情况
    在这里插入图片描述
    附3 : 库存表情况(仍为初始值)
    在这里插入图片描述

    注意 :在将Mapper.xml中数据库更新语句书写正确后 , 然后访问出现如下错误 或ReadTime Out异常,重新刷新页面即可解决
    com.codingapi.txlcn.common.exception.TxManagerException: 
    attempts to join the non-existent transaction group. [cb2f2e3423878daebdd28d0a684e68c6@springclooud-inventory]
    
     
     
    • 1
    • 2

    在这里插入图片描述

    在服务网关中配置LCN

    当前LCN-5.0.2版本使用的rpc协议, 所以配置在配置时不收网关的影响
    具体请看项目案例: 百战商城项目案例

    如果想继续学习LCN请看这个大佬的博客

                                    </div>
                <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-60ecaf1f42.css" rel="stylesheet">
                                                <div class="more-toolbox">
                <div class="left-toolbox">
                    <ul class="toolbox-list">
                        
                        <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count">5</span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;1582594662_002&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/qq_43371556">
                    <img src="https://profile.csdnimg.cn/E/3/6/3_qq_43371556" class="avatar_pic" username="qq_43371556">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/1x/2.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/qq_43371556" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">时间静止不是简史</a></span>
                                            </div>
                    <div class="text"><span>发布了192 篇原创文章</span> · <span>获赞 985</span> · <span>访问量 29万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=qq_43371556" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
编辑推荐: 本文来自于csdn,本篇文章主要介绍了LCN5.0.2有3种模式,分别是LCN模式,TCC模式,TXC模式,希望对您的学习 有所帮助。 一、简介 LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果。 LCN模式: LCN模式是通过代理Connection的方式实现对本地事务的操作,然后在由TxManager统一协调控制事务。当本地事务提交回滚或者关闭连接时将会执行假操作,该代理的连接将由LCN连接池管理。 该模式的特点: - 该模式对代码的嵌入性为低。 - 该模式仅限于本地存在连接对象且可通过连接对象控制事务的模块。 - 该模式下的事务提交与回滚是由本地事务方控制,对于数据一致性上有较高的保障。 - 该模式缺陷在于代理的连接需要随事务发起方一共释放连接,增加了连接占用的时间。 TCC模式: TCC事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。 该模式的特点: - 该模式对代码的嵌入性高,要求每个业务需要写三种步骤的操作。 - 该模式对有无本地事务控制都可以支持使用面广。 - 数据一致性控制几乎完全由开发者控制,对业务开发难度要求高。 TXC模式: TXC模式命名来源于淘宝,实现原理是在执行SQL之前,先查询SQL的影响数据,然后保存执行的SQL快走信息和创建锁。当需要回滚的时候就采用这些记录数据回滚数据库,目前锁实现依赖redis分布式锁控制。 该模式的特点: - 该模式同样对代码的嵌入性低。 - 该模式仅限于对支持SQL方式的模块支持。 - 该模式由于每次执行SQL之前需要先查询影响数据,因此相比LCN模式消耗资源与时间要多。 - 该模式不会占用数据库的连接资源。 二、原理 核心步骤 1.创建事务组 是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。 2.添加事务组 添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息添加通知给TxManager的操作。 3.关闭事务组 是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager的动作。当执行完关闭事务组的方法以后,TxManager将根据事务组信息来通知相应的参与模块提交或回滚事务事务控制原理 LCN事务控制原理是由事务模块TxClient下的代理连接池与TxManager的协调配合完成的事务协调控制。 TxClient的代理连接池实现了javax.sql.DataSource接口,并重写了close方法,事务模块在提交关闭以后TxClient连接池将执行"假关闭"操作,等待TxManager协调完成事务以后在关闭连接。 对于代理连接池的优化 自动超时机制,任何通讯都有最大超时限制,参与模块在等待通知的状态下也有最大超时限制,当超过时间限制以后事务模块将先确认事务状态,然后再决定执行提交或者回滚操作,主要为了给最大资源占用时间加上限制。 智能识别创建不同的连接 对于只读操作、非事务操作LCN将不开启代理功能,返回本地连接对象,对于补偿事务的启动方将开启回滚连接对象,执行完业务以后马上回滚事务LCN连接重用机制 当模块在同一次事务下被重复执行时,连接资源会被重用,提高连接的使用率。 事务补偿机制 为什么需要事务补偿? 事务补偿是指在执行某个业务方法时,本应该执行成功的操作却因为服务器挂机或者网络抖动等问题导致事务没有正常提交,此种场景就需要通过补偿来完成事务,从而达到事务的一致性。 补偿机制的触发条件? 当执行关闭事务组步骤时,若发起方接受到失败的状态后将会把该次事务识别为待补偿事务,然后发起方将该次事务数据异步通知给TxManager。TxManager接受到补偿事务以后先通知补偿回调地址,然后再根据是否开启自动补偿事务状态来补偿或保存该次切面事务数据。 补偿事务机制 LCN的补偿事务原理是模拟上次失败事务的请求,然后传递给TxClient模块然后再次执行该次请求事务。 模拟场景演示 若存在事务发起方、参与方A、参与方B。调用关系图如下 那么他们正常执行业务的时序图为: 若参与方B出现异常,那么他们的业务时序图为: 若他们的调用关系是这样的情况 此时发生参与方B出现异常时他们的时序图为: 三、使用 环境: SpringBoot 2.0.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值