spring boot 分布式事务解决方案LCN

对比LCN和saga(华为apache孵化器项目) ,LCN使用代理连接池封装补偿方法,saga需要手工写补偿方法,相对来说LCN使用更加方便。

参考官方地址:

https://github.com/codingapi/tx-lcn/wiki/TxManager%E5%90%AF%E5%8A%A8%E8%AF%B4%E6%98%8E

1.    原理

1.     事务控制原理

LCN事务控制原理是由事务模块TxClient下的代理连接池与TxManager的协调配合完成的事务协调控制。

TxClient的代理连接池实现了javax.sql.DataSource接口,并重写了close方法,事务模块在提交关闭以后TxClient连接池将执行"假关闭"操作,等待TxManager协调完成事务以后在关闭连接。

2.     调用时序图

1.     正常

2.     异常

2.    服务端

tx-manager 4.1.0

3.    客户端

1.     pom添加依赖


<properties>

<lcn.last.version>4.1.0</lcn.last.version>

</properties>


<dependency>

<groupId>org.mybatis.spring.boot</groupId>

<artifactId>mybatis-spring-boot-starter</artifactId>

<version>1.1.1</version>

</dependency>

<dependency>

<groupId>com.codingapi</groupId>

<artifactId>transaction-springcloud</artifactId>

<version>${lcn.last.version}</version>

<exclusions>

<exclusion>

<groupId>org.slf4j</groupId>

<artifactId>*</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>com.codingapi</groupId>

<artifactId>tx-plugins-db</artifactId>

<version>${lcn.last.version}</version>

<exclusions>

<exclusion>

<groupId>org.slf4j</groupId>

<artifactId>*</artifactId>

</exclusion>

</exclusions>

</dependency>

2.    配置文件


#Ribbon的负载均衡策略:随机

#ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

#由于springcloud默认是开启的重试机制,开启次机制以后会导致当springcloud请求超时时会重复调用业务模块,从而会引发数据混乱,因此建议将其禁用。对于网络模块超时等故障问题建议使用hytrix方式。

#ribbon.MaxAutoRetriesNextServer=0

tm:

manager:

url: http://localhost:8899/tx/manager/

ribbon:

NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

MaxAutoRetriesNextServer: 0

init-db:true

hystrix:

command:

default:

execution:

isolation:

thread:

timeoutInMilliseconds: 6000

3.     Service包下处理http请求和对服务器的连接


package com.svw.tbox.tcloud.commons.ms.service;

import com.codingapi.tx.netty.service.TxManagerHttpRequestService;

import com.lorne.core.framework.utils.http.HttpUtils;

import org.springframework.stereotype.Service;

@Service

publicclass TxManagerHttpRequestServiceImpl implements TxManagerHttpRequestService{

@Override

public String httpGet(String url) {

//GET请求前

String res = HttpUtils.get(url);

//GET请求后

returnres;

}

@Override

public String httpPost(String url, String params) {

//POST请求前

String res = HttpUtils.post(url,params);

//POST请求后

returnres;

}

}


package com.svw.tbox.tcloud.commons.ms.service;

 

import com.codingapi.tx.config.service.TxManagerTxUrlService;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Service;

 

@Service

public class TxManagerTxUrlServiceImpl implements TxManagerTxUrlService{

 

    @Value("${tm.manager.url}")

    private String url;

 

    @Override

    public String getTxUrl() {

    //load tm.manager.url

        return url;

    }

}

4.    启动类配置代理连接池


import javax.sql.DataSource;

import org.mybatis.spring.annotation.MapperScan;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

import org.springframework.cloud.netflix.hystrix.EnableHystrix;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.core.env.Environment;

import com.alibaba.druid.pool.DruidDataSource;

@SpringBootApplication

@EnableDiscoveryClient

@EnableHystrix

@MapperScan(basePackages = "com.svw.tbox.tcloud.commons.ms.dao")

@ComponentScan(basePackages = { "com.svw.tbox.tcloud" })

publicclass MsApplication {

……

@Autowired

private Environment env;

@Bean

public DataSource dataSource() {

DruidDataSource dataSource = new DruidDataSource();

dataSource.setUrl(env.getProperty("spring.datasource.url"));

dataSource.setUsername(env.getProperty("spring.datasource.username"));//用户名

dataSource.setPassword(env.getProperty("spring.datasource.password"));//密码

dataSource.setInitialSize(2);

dataSource.setMaxActive(20);

dataSource.setMinIdle(0);

dataSource.setMaxWait(60000);

dataSource.setValidationQuery("SELECT 1");

dataSource.setTestOnBorrow(false);

dataSource.setTestWhileIdle(true);

dataSource.setPoolPreparedStatements(false);

returndataSource;

}

5.    测试代码

调用方tcloud-mds => 参与方tcloud-commons

1.     调用方:tcloud-mds


package com.svw.tbox.tcloud.commons.api.feign;

import org.springframework.cloud.netflix.feign.FeignClient;

import com.svw.tbox.tcloud.commons.api.config.TxFeignConfiguration;

import com.svw.tbox.tcloud.commons.api.service.SysErrorCodeMappingService;

/**

* <p>ClassName: SysErrorCodeMappingFeign</p>

* <p>Description: 远程调用错误码服务</p>

* <p>Author: hurf</p>

* <p>Date: 2017年12月11日</p>

*/

@FeignClient(value = "tcloud-commons-ms")

publicinterface SysErrorCodeMappingFeign extends SysErrorCodeMappingService {

}

2.     事务发起@TxTransaction(isStart=true)


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.codingapi.tx.annotation.TxTransaction;

import com.svw.tbox.tcloud.commons.api.entity.SysErrorCodeMapping;

import com.svw.tbox.tcloud.commons.api.feign.SysErrorCodeMappingFeign;

import com.svw.tbox.tcloud.commons.api.service.CmnService;

import com.svw.tbox.tcloud.commons.api.service.JedisTemplate;

import com.svw.tbox.tcloud.commons.util.DateUtil;

import com.svw.tbox.tcloud.mds.entity.ThUserLogin;

/**

* @Title<p>ClassName: UserTokenService</p>

* @Description<p>Description: 登录服务</p>

* @Author<p>Author: hurf</p>

* @Date<p>Date: 2018年2月6日</p>

*/

@Service

publicclass UserTokenService extends CmnService<ThUserLogin>{

@Autowired

private JedisTemplate jedisTemplate;

@Autowired

private SysErrorCodeMappingFeign sysErrorCodeMappingFeign;

@Transactional

@TxTransaction(isStart=true)

public String add(SysErrorCodeMapping sysErrorCodeMapping) {

// 远程调用新增

sysErrorCodeMappingFeign.add(sysErrorCodeMapping);

// 本地新增db

insertSelective(ThUserLogin.builder().accessToken(sysErrorCodeMapping.getApiCode())

.refreshToken(sysErrorCodeMapping.getInnerErrorCode()).createBy("测试事务").build());

//本地缓存事务

jedisTemplate.set("isStart", DateUtil.getNow());

//      int ii = 1/0;//异常

return"测试分布式事务成功";

}

}

3.     事务参与方tcloud-commons-ms: @Transactional


@RestController

publicclass SysErrorCodeMappingController implements SysErrorCodeMappingService {

@Autowired

private MsService msService;

@ApiOperation("添加错误码信息")

@Override

public SystemResponse add(@RequestBody SysErrorCodeMapping sysErrorCodeMapping) {

returnmsService.add(sysErrorCodeMapping);

}

。。。。。。


importcom.codingapi.tx.annotation.ITxTransaction;

@Service

@CacheConfig(cacheNames = "sys-code-resource")

publicclass MsService implements ITxTransaction{

@Autowired

private JedisTemplate jedisTemplate;

@Autowired

private SysErrorCodeMappingMapper sysErrorCodeMappingMapper;

/**

* <p>Title: 事务参与方</p>

* <p>Description: </p>

* @param sysErrorCodeMapping

* @return

*/

@Transactional

public SystemResponse add(SysErrorCodeMapping sysErrorCodeMapping) {

//db操作

sysErrorCodeMapping.setVersion(1);

sysErrorCodeMapping.setDelFlag(Short.valueOf("0"));

sysErrorCodeMapping.setCreatedBy("admin");

sysErrorCodeMapping.setCreateDate(new Date());

sysErrorCodeMappingMapper.insertSelective(sysErrorCodeMapping);

//redis操作

jedisTemplate.set("addTest"+DateUtil.getNow(),"tttttttttttttttttttttt");

return ResultUtil.success(refreshAll());

}

6.     效果

启动两个微服务,访问调用方接口

1.     正常情况

2.     异常回滚情况

删除刚刚的测试数据,开启异常情况:


@Transactional

@TxTransaction(isStart=true)

public String add(SysErrorCodeMapping sysErrorCodeMapping) {

// 远程调用新增

sysErrorCodeMappingFeign.add(sysErrorCodeMapping);

// 本地新增db

insertSelective(ThUserLogin.builder().accessToken(sysErrorCodeMapping.getApiCode())

.refreshToken(sysErrorCodeMapping.getInnerErrorCode()).createBy("测试事务").build());

//本地缓存事务

jedisTemplate.set("isStart", DateUtil.getNow());

intii = 1/0;//异常

return"测试分布式事务成功";

}

发现mysql已经回滚了,但是redis没有回滚 =》 目前只支持db分布式事务。

---------------------
作者:行一米
来源:CSDN
原文:https://blog.csdn.net/baidu_36415076/article/details/79599619?utm_source=copy
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/dousnl/p/9772632.html

时间: 2024-10-05 20:03:43

spring boot 分布式事务解决方案LCN的相关文章

Spring Cloud 分布式事务管理

Spring Cloud 分布式事务管理 在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及网络不可靠的概率. Spring Cloud 分布式事务管理 单体式架构 微服务架构 优点: 缺点: 分布式事务的引入 分布式事务解决方案 基于XA协议的两阶段提交 消息事务+最终一致性 TCC编程模式 具体实现 LCN ByteTCC 在说微服务的优缺点时,有对比才会更加明显,首先说一下单体式结构 单体式架构 在单体式架构中,系统通常采

微服务架构下分布式事务解决方案——阿里云GTS

https://blog.csdn.net/jiangyu_gts/article/details/79470240 1 微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,很多互联网行业巨头.开源社区等都开始了微服务的讨论和实践.Hailo有160个不同服务构成,NetFlix有大约600个服务.国内方面,阿里巴巴.腾讯.360.京东.58同城等很多互联网公司都进行了微服务化实践.当前微服务的开

猪齿鱼_学习_01_事务(三)_分布式事务解决方案

一.前言 本文承接上一节:猪齿鱼_学习_01_事务(二)_分布式理论 第一节中,我们谈到了本地事务数据库断电时的故障恢复: 我们在执行事务的时候数据库首先会记录下这个事务的redo操作日志,然后才开始真正操作数据库,在操作之前首先会把日志文件写入磁盘,那么当突然断电的时候,即使操作没有完成,在重新启动数据库时候,数据库会根据当前数据的情况进行undo回滚或者是redo前滚,这样就保证了数据的强一致性. 分布式系统的核心就是处理各种异常情况,这也是分布式系统复杂的地方,因为分布式的网络环境很复杂,

阿里开源分布式事务解决方案 Fescar 全解析

广为人知的阿里分布式事务解决方案:GTS(Global Transaction Service),已正式推出开源版本,取名为"Fescar",希望帮助业界解决微服务架构下的分布式事务问题,今天我们一起来深入了解. FESCAR on GitHub https://github.com/alibaba/fescar 微服务倡导将复杂的单体应用拆分为若干个功能简单.松耦合的服务,这样可以降低开发难度.增强扩展性.便于敏捷开发.当前被越来越多的开发者推崇,系统微服务化后,一个看似简单的功能,

常用的分布式事务解决方案

众所周知,数据库能实现本地事务,也就是在同一个数据库中,你可以允许一组操作要么全都正确执行,要么全都不执行.这里特别强调了本地事务,也就是目前的数据库只能支持同一个数据库中的事务.但现在的系统往往采用微服务架构,业务系统拥有独立的数据库,因此就出现了跨多个数据库的事务需求,这种事务即为"分布式事务".那么在目前数据库不支持跨库事务的情况下,我们应该如何实现分布式事务呢?本文首先会为大家梳理分布式事务的基本概念和理论基础,然后介绍几种目前常用的分布式事务解决方案.废话不多说,那就开始吧-

分布式事务 解决方案

事务的概念来源于业务过程.在许多情况下我们都希望能够确保在一个过程中执行的所有操作是完全成功的.在集中式系统中,事务被广泛用于服务器端和数据库系统,控制数据的操作.随着分布式计算的发展,事务在分布式计算领域中也得到了广泛的应用,但是分布式系统架构中,分布式事务问题是一个绕不过去的挑战.而微服务架构的流行,让分布式事问题日益突出! 下面我们以电商购物支付流程中,在各大参与者系统中可能会遇到分布式事务问题的场景进行详细的分析! 如上图所示,假设三大参与平台(电商平台.支付平台.银行)的系统都做了分布

基于金融系统的分布式事务解决方案

分布式系统架构中,分布式事务问题是一个绕不过去的挑战.而微服务架构的流行,让分布式事问题日益突出! 下面我们以电商购物支付流程中,在各大参与者系统中可能会遇到分布式事务问题的场景进行详细的分析! 如上图所示,假设三大参与平台(电商平台.支付平台.银行)的系统都做了分布式系统架构拆分,按上数中的流程步骤进行分析: 1.电商平台中创建订单:预留库存.预扣减积分.锁定优惠券,此时电商平台内各服务间会有分布式事务问题,因为此时已经要跨多个内部服务修改数据: 2.支付平台中创建支付订单(选银行卡支付):查

微服务架构的分布式事务解决方案

微服务架构的分布式事务解决方案 标签:分布式事务,微服务,消息最终一致性,分布式事务解决方案发布于 2016-07-16 18:39:05 分布式系统架构中,分布式事务问题是一个绕不过去的挑战.而微服务架构的流行,让分布式事问题日益突出! 下面我们以电商购物支付流程中,在各大参与者系统中可能会遇到分布式事务问题的场景进行详细的分析! 如上图所示,假设三大参与平台(电商平台.支付平台.银行)的系统都做了分布式系统架构拆分,按上数中的流程步骤进行分析: 1.电商平台中创建订单:预留库存.预扣减积分.

java微服务架构的分布式事务解决方案

java微服务架构的分布式事务解决方案 课程目录如下: 1.课程介绍20分钟2.解决方案的效果演示(结合支付系统真实应用场景)45分钟3.常用的分布式事务解决方案介绍47分钟4.消息发送一致性(可靠消息的前提保障)20分钟5.消息发送一致性的异常流程处理16分钟6.常规MQ队列消息的处理流程和特点12分钟7.消息重复发送问题及业务接口的幂等性设计18分钟8.可靠消息最终一致性方案1(本地消息服务)的设计19分钟9.可靠消息最终一致性方案2(独立消息服务)的设计24分钟10.可靠消息服务的设计与实