| 
         
          
          | 
		   
               
                |  |   
                |  spring 
                      boot 分布式事务解决方案LCN |   
                |  |  
                |  | 
  
  |  | 3251  次浏览  28 |  | 2019-9-25 | 
 |  
              |  |   
                | 
                     
                        | 
                             
                              | 
                                   
                                    | 编辑推荐: |   
                                    | 本文来自于 
                                        csdn,将从原理,调用时序图,客户端,启动类配置代理连接池,测试代码和效果这几个方面来阐述分布式事务解决方案LCN。 |  |  对比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添加依赖 
 								 
         							
                              | <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 
 								 
         							
                              | 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(),"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分布式事务。 |  
                     
                      |  |  |  
                          
         
          
    | 3251 
       次浏览  28 |  |  |  |  |  |  |