ITPub博客

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

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

作者:penny_liang 时间:2019-12-16 11:37:11 0 删除 编辑

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

参考官方地址

1. 原理

1. 事务控制原理

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

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

2. 调用时序图

1. 正常

2. 异常

2. 服务端

tx-manager 4.1.0

3. 客户端

1. pom添加依赖

4.1.0

org.mybatis.spring.boot

mybatis-spring-boot-starter

1.1.1

com.codingapi

transaction-springcloud

${lcn.last.version}

org.slf4j

*

com.codingapi

tx-plugins-db

${lcn.last.version}

org.slf4j

*

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

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;

/**

*

ClassName: SysErrorCodeMappingFeign

*

Description: 远程调用错误码服务

*

Author: hurf

*

Date: 2017年12月11日

*/

@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

ClassName: UserTokenService

* @Description

Description: 登录服务

* @Author

Author: hurf

* @Date

Date: 2018年2月6日

*/

@Service

publicclass UserTokenService extends CmnService{

@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;

/**

*

Title: 事务参与方

*

Description:

* @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(),"ttttttttttt ttttttttttt");

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分布式事务。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/714/viewspace-3160677/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-04-12

  • 博文量
    189
  • 访问量
    1747