文章目录

  • 简介
  • 实现原理
  • 入门demo

简介

LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果。

LCN5.0.2有3种模式,分别是LCN模式,TCC模式,TXC模式

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.LCN客户端(发起方和参与方都必须要注册到事务协调者中), 建立一个长连接。(长连接 减宽带 但是消耗内存 连接后不断开)

2.订单服务(发起方)调用库存服务接口(参与方)之前,会向TxManager事务协调者创建一个事务的分组id。
3.订单服务(发起方)调用库存服务接口(参与方)的时候,会在请求头(底层是HTTP协议,LCN底层重写了Feigin客户端)中存放该事务的分组id,给库存服务。

(TxClient的代理连接池实现了Javax.sql.DataSource接口,并重写了close方法,事务模块在提交关闭后,TxClient连接池将执行‘假关闭’操作,等待TxManager协调完成事务后再关闭连接
4.如果库存服务获取到请求头中有对应的事务分组id,库存服务业务逻辑代码执行完毕的,会采用假关闭,不会提交该事务。

(微服务里面的服务和服务之间 协调在一起 通过注册中心。
分布式是事务中, 解决事务和事务之间的关系 靠的是类似的平台 TxManager 去协调事务
)

5.参与方在什么时候提交事务,不能一直不提交。
肯定在发起方 执行成功下。
订单服务(发起方)调用库存服务接口(参与方)之后,如果订单服务(发起方)执行没有问题的下,
订单服务(发起方)使用对应的事务分组id,通知给TxManager事务协调者,让后TxManager事务协调者在根据该事务分组id,通知给所有的参与方提交事务。

PS:长连接 好处减少宽带传输 弊端比较占内存。

使用LCN很简单 加个注解就OK了

入门demo

废话不多说,开整

SQL建表语句(在txlcn-tm模块的resource目录下)

/*Navicat Premium Data TransferSource Server         : localSource Server Type    : MySQLSource Server Version : 100309Source Host           : localhost:3306Source Schema         : tx-managerTarget Server Type    : MySQLTarget Server Version : 100309File Encoding         : 65001Date: 29/12/2018 18:35:59
*/
CREATE DATABASE IF NOT EXISTS  `tx-manager` DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
USE `tx-manager`;SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for t_tx_exception
-- ----------------------------
DROP TABLE IF EXISTS `t_tx_exception`;
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,`ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 待处理 1已处理',`remark` varchar(10240) NULL DEFAULT NULL COMMENT '备注',`create_time` datetime(0) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 967 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

下载源码并编译
源码下载地址:https://github.com/codingapi/tx-lcn
工程目录

修改txlcn-tm的配置文件application.properties

spring.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=123456
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update# TM后台登陆密码,默认值为codingapi
tx-lcn.manager.admin-key=123456

注意:个人修改了数据库的名称,和用户名密码,TM的后台登录密码,其他根据自己的实际情况修改

txlcn-tm的pom修改,放开配置

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>2.6</version><configuration><archive><manifest><mainClass>com.codingapi.txlcn.tm.TMApplication</mainClass><addClasspath>true</addClasspath><classpathPrefix>lib/</classpathPrefix></manifest><manifestEntries><Class-Path>./</Class-Path></manifestEntries></archive><excludes><exclude>config/**</exclude></excludes></configuration></plugin><plugin><artifactId>maven-assembly-plugin</artifactId><configuration><appendAssemblyId>false</appendAssemblyId><descriptors><descriptor>src/main/build/package.xml</descriptor></descriptors></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin>

注掉配置

<!--docker 构建--><!--<plugin><groupId>com.spotify</groupId><artifactId>docker-maven-plugin</artifactId><version>1.0.0</version><configuration><imageName>codingapi/txlcn-tm</imageName><dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory><resources><resource><targetPath>/</targetPath><directory>${project.build.directory}</directory><include>${project.build.finalName}.jar</include></resource></resources><imageTags><imageTag>5.0.2</imageTag></imageTags><serverId>docker-hub</serverId><registryUrl>https://index.docker.io/v1/</registryUrl></configuration></plugin>
-->

最后使用maven编译,去掉test,否则编译很慢

启动txlcn-tm模块

启动后打开后台地址http://localhost:7970,初始密码是codingapi,我这里改成了123456

项目配置

本文以下订单扣库存举例。分为2个服务,并注册到eureka上

sql文件

test1库goods表,test2库order_form表

/*Navicat MySQL Data TransferSource Server         : localhostSource Server Type    : MySQLSource Server Version : 50712Source Host           : localhost:3306Source Schema         : test1Target Server Type    : MySQLTarget Server Version : 50712File Encoding         : 65001Date: 09/01/2020 14:52:01
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for goods
-- ----------------------------
DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods`  (`id` int(11) NOT NULL AUTO_INCREMENT,`goods_id` int(10) NULL DEFAULT NULL,`stock` int(10) NULL DEFAULT NULL,`group_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of goods
-- ----------------------------
INSERT INTO `goods` VALUES (1, 31, 100, '');SET FOREIGN_KEY_CHECKS = 1;
/*Navicat MySQL Data TransferSource Server         : localhostSource Server Type    : MySQLSource Server Version : 50712Source Host           : localhost:3306Source Schema         : test2Target Server Type    : MySQLTarget Server Version : 50712File Encoding         : 65001Date: 09/01/2020 13:53:07
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for order_form
-- ----------------------------
DROP TABLE IF EXISTS `order_form`;
CREATE TABLE `order_form`  (`id` int(11) NOT NULL AUTO_INCREMENT,`goods_id` int(20) NULL DEFAULT NULL,`goods_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,`user_id` int(10) NULL DEFAULT NULL,`create_time` timestamp(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0),PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;

eureka

eureka代码不上了,很简单,上下配置文件

application.yml

server:port: 6868
eureka:client:register-with-eureka: falsefetch-registry: falseservice-url:defaultZone: http://127.0.0.1:${server.port}/eureka/server:enable-self-preservation: false
spring:application:name: eureka

order服务

controller

package com.wangtao.controller;import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.wangtao.dao.OrderDao;
import com.wangtao.enity.Order;
import com.wangtao.feign.OrderFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Date;@RestController
public class OrderController {@Autowiredprivate OrderDao orderDao;@Autowiredprivate OrderFeign orderFeign;@Transactional(rollbackFor = Exception.class)@LcnTransaction@RequestMapping("/createOrder")public String createOrder (){int i = 0;try {Order order = new Order();order.setGoodsName("图片");order.setGoodsId(31);order.setUserId(1);order.setCreateTime(new Date());orderDao.save(order);i = orderFeign.updateGoodsStock();int j=1/0;} catch (Exception e) {e.printStackTrace();throw new RuntimeException("下单失败",e);}return "下单成功";}}

dao

package com.wangtao.dao;import com.wangtao.enity.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;@Repository
public interface  OrderDao extends JpaRepository<Order, Integer>, JpaSpecificationExecutor<Order> {}

enity

package com.wangtao.enity;import lombok.Data;import javax.persistence.*;
import java.util.Date;@Data
@Entity
@Table(name = "order_form")
public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增类型的主键private int id;@Column(name = "goods_id")private int goodsId;@Column(name = "goods_name")private String goodsName;@Column(name="user_id")private int userId;@Column(name = "create_time")private Date createTime;}

feign

package com.wangtao.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;@FeignClient(name = "goods")
@Component
public interface OrderFeign {@RequestMapping(value = "/goods/updateGoodsStock", method = RequestMethod.POST)int updateGoodsStock();}

启动类

package com.wangtao;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;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableDistributedTransaction
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}}

配置文件

server:port: 9001
spring:application:name: order #指定服务名datasource:driverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=UTF8&useSSL=falseusername: rootpassword: 123456jpa:database: MySQLshow-sql: truecloud:refresh:refreshable: none
eureka:client:service-url:defaultZone: http://127.0.0.1:6868/eureka/instance:prefer-ip-address: true
tx-lcn:client:manager-address: 127.0.0.1:8070logger:enabled: true

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>parent</artifactId><groupId>com.wangtao</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>order</artifactId><dependencies><!-- 添加Eureka的依赖 --><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>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-rest</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>42.2.4</version></dependency><dependency><groupId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--<dependency>--><!--<groupId>org.springframework.cloud</groupId>--><!--<artifactId>spring-cloud-starter-config</artifactId>--><!--</dependency>--><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.9.13</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.3.13.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId></dependency><dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier></dependency><dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-client</artifactId><version>2.0.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</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><!--分布式事务依赖  结束--></dependencies>
</project>

goods服务

controller

package com.wangtao.controller;import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.codingapi.txlcn.tc.annotation.TxcTransaction;
import com.wangtao.dao.GoodsDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/goods")
public class GoodsController {@Autowiredprivate GoodsDao goodsDao;@RequestMapping("/updateGoodsStock")@Transactional(rollbackFor = Exception.class)@LcnTransaction //分布式事务注解public int updateGoodsStock(){int i = goodsDao.updateGoodsStock();return 1;}@RequestMapping("/updateGoodsStockTcc")@Transactional(rollbackFor = Exception.class)//@TccTransaction@TxcTransactionpublic int updateGoodsStockTcc(){int i = goodsDao.updateGoodsStock();return 1;}
}

dao

package com.wangtao.dao;import com.wangtao.entity.Goods;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;@Repositorypublic interface  GoodsDao extends JpaRepository<Goods, Integer>, JpaSpecificationExecutor<Goods> {@Modifying@Query(value = "update goods set stock=stock-1 where goods_id=31 and stock>0",nativeQuery = true)public int updateGoodsStock();}

entity

package com.wangtao.entity;import lombok.Data;import javax.persistence.*;@Entity
@Data
@Table(name = "goods")
public class Goods {@Id@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增类型的主键private int id;@Column(name = "goods_id")private int goodsId;private int stock;}

启动类

package com.wangtao;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 GoodsApplication {public static void main(String[] args) {SpringApplication.run(GoodsApplication.class, args);}}

配置文件

server:port: 9002
spring:application:name: goods #指定服务名datasource:driverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=UTF8&useSSL=falseusername: rootpassword: 123456jpa:database: MySQLshow-sql: truecloud:refresh:refreshable: none
eureka:client:service-url:defaultZone: http://127.0.0.1:6868/eureka/instance:prefer-ip-address: true
tx-lcn:client:manager-address: 127.0.0.1:8070logger:enabled: true

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>parent</artifactId><groupId>com.wangtao</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>goods</artifactId><properties><java.version>1.8</java.version></properties><dependencies><!-- 添加Eureka的依赖 --><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>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-rest</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--<dependency>--><!--<groupId>org.springframework.cloud</groupId>--><!--<artifactId>spring-cloud-starter-config</artifactId>--><!--</dependency>--><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.3.13.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId></dependency><dependency><groupId>de.codecentric</groupId><artifactId>spring-boot-admin-starter-client</artifactId><version>2.0.2</version></dependency><!-- 热部署 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><!-- <version>2.0.4.RELEASE</version>--><!-- 启用 --><optional>true</optional></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</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><!--分布式事务依赖  结束--></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

分别启动两个服务并注册到eureka上,并访问http://localhost:9001/createOrder
发现基于lcn模式的数据库表中并没有增加数据,说明分布式事务起作用了

下面演示tcc模式

eureka配置不变

order服务

OrderController增加

    @Transactional(rollbackFor = Exception.class)@RequestMapping("/createTccOrder")@LcnTransactionpublic String createTccOrder (@RequestParam int num){int i = 0;try {Order order = new Order();order.setGoodsName("图片");order.setGoodsId(31);order.setUserId(1);order.setCreateTime(new Date());orderDao.save(order);i = orderFeign.updateGoodsStockTcc();int j=1/num;} catch (Exception e) {e.printStackTrace();throw new RuntimeException("下单失败",e);}return "下单成功";}

OrderFeign增加

    @RequestMapping(value = "/goods/updateGoodsStockTcc", method = RequestMethod.POST)int updateGoodsStockTcc();

goods服务

GoodsController增加

 @RequestMapping("/updateGoodsStockTcc")@Transactional(rollbackFor = Exception.class)@TccTransaction(propagation = DTXPropagation.SUPPORTS,cancelMethod = "cancelUpdate",confirmMethod = "confirmUpdate" ,executeClass = GoodsController.class)public int updateGoodsStockTcc(){int i = goodsDao.updateGoodsStockTcc(TracingContext.tracing().groupId());return 1;}public void confirmUpdate() {log.info("成功");}@Transactional(rollbackFor = Exception.class)public void cancelUpdate() {log.error("失败,正在回退");goodsDao.cancelUpdate(TracingContext.tracing().groupId());log.error("回退成功");}

GoodsDao增加

    @Modifying@Query(value = "update goods set stock=stock-1,group_id=:groupId where goods_id=31 and stock>0",nativeQuery = true)public int updateGoodsStockTcc(@Param("groupId") String groupId);@Modifying@Query(value = "update goods set stock=stock+1 where group_id=:groupId",nativeQuery = true)void cancelUpdate(@Param("groupId") String groupId);

Goods增加

    @Column(name = "group_id")private String groupId;

启动2个服务注册到eureka上
输入网址正常情况下


order_form表

goods表

恢复原始数据,测试报错情况下


order_form表

goods表

ok,测试完毕,另外一种txc模式大家自行探索吧,溜了。。。

分布式事务框架lcn入门demo相关推荐

  1. 基于SpringCloud的分布式事务框架(LCN)

    框架特点 支持各种基于spring的db框架 兼容springcloud.dubbo 使用简单,代码完全开源 基于切面的强一致性事务框架 高可用,模块可以依赖dubbo或springcloud的集群方 ...

  2. LCN分布式事务框架

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

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

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

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

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

  5. 分布式事务讲解 - TX-LCN分布式事务框架(含LCN、TCC、TXC三种模式)

    分布式事务讲解 - TX-LCN分布式事务框架(含LCN.TCC.TXC三种模式) 分布式事务系列博客: TX-LCN框架原理 LCN 原理及主要特点 代码实现 实现场景 创建数据库及表(三个数据库, ...

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

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

  7. 关于分布式事务: 阿里开源的分布式事务框架 Seata 和 LCN的分析

    之前使用过LCN分布式事务, 最近看到面试者简历中另一种方案 Seata, 通过它来在实战中解决分布式事务的问题.故 去简单了解了一下Seata是什么, 和LCN的区别在哪里, 如果是你 你怎么选择解 ...

  8. Spring Cloud的分布式事务框架压测第一轮

    前言 分布式事务对微服务开发者而言是既想努力避免又无法完全回避的蛋疼问题.通过使用分布式事务处理框架可以很大程度上解决分布式事务所带来的事务性能.可靠性问题,以及引入的编码复杂性.本文由海信HICS技 ...

  9. 关于tx-lcn分布式事务框架的几个问题

    本文来说下tx-lcn分布式事务框架 文章目录 LCN介绍 LCN解决方案 事务控制原理 核心步骤 实战之-TxManager 建中间件数据库 TM服务搭建 TM服务中 application.pro ...

最新文章

  1. 重新开始 2011/11/25
  2. linux的fork语句,Linux C/C++——fork()函数基础
  3. 音频插件组合:Arturia Prophet V3 for Mac
  4. docker 安装 mysql 并映射数据库存放路径及配置文件
  5. Android基础知识学习
  6. 关于用户自定义控件与引用该控件的页面之间的javascript脚本冲突
  7. P-Called-Party-ID 头域的应用说明
  8. .net byte转java byte_「Java知识收集整理」Java语法的基础
  9. java异常类型及处理
  10. CentOs安装pyhive
  11. 2020.11.14--AE--图层八种形式、图层面板图标、查看器面板
  12. 微信永久封号怎么解封?微信社交场景被限制解决办法
  13. 子载波间隔与符号长度
  14. mysql无法打开excel_关于Navicat将Excel数据导入到MySQL中出现无法打开文件错误
  15. 基于高通量表型的QTL定位揭示了甘蓝型油菜耐盐胁迫的遗传结构
  16. 除了照片征集、视频征集,fotoo还可以征集什么?
  17. 2022年全球区块链审计公司排行榜
  18. 第十一章 “万金油”的String,为什么不好用了
  19. JavaScript时间换算单位
  20. 亿图脑图MindMaster(Pro)

热门文章

  1. SetDlgItemText
  2. 语音识别基本原理学习
  3. Springboot:商品库存并发更新,乐观锁失败重试机制
  4. 类模板中的友元,友元类
  5. Unity记录3.1-地图-TileMap简单使用、鼠标拖动放置Tile
  6. garch dcc用matlab,用matlab工具箱怎么对garch模型做...
  7. 人力资源管理的毕业论文选题推荐?
  8. 数据化决策-数据分析与高效经营1
  9. 查看表空间使用率(包括临时表空间)
  10. 深度学习第四次培训(SVM算法)