网上貌似有很多微服务的框架,找了半天,貌似只有TX-LCN
有完整的搭建,所以先摘抄一些,应对面试
介绍
TX-LCN分布式事务框架,LCN并不生产事务,LCN只是本地事务的协调工,LCN是一个高性能的分布式事务框架,兼容dubbo、springcloud框架,支持RPC框架拓展,支持各种ORM框架、NoSQL、负载均衡、事务补偿
特性
-
一致性,通过TxManager协调控制与事务补偿机制确保数据一致性
-
易用性,仅需要在业务方法上添加@TxTransaction注解即可
@TxTransaction注解是分布式事务的标示。
若存在业务方法:a->b b->c b->d,那么开启分布式事务注解的话,只需要在a方法上添加@TxTransaction即可。
- 高可用,项目模块不仅可高可用部署,事务协调器也可集群化部署
- 扩展性,支持各种RPC框架扩展,支持通讯协议与事务模式扩展
官方文档
https://www.txlcn.org/zh-cn/docs/preface.html
流程图实现
- 服务发起者 在事务协调者内创建事务组,并将本事务加入事务组
- 事务参与者加入事务组,直到有结束标记出现
- 事务协调者向所有的事务参与者发送询问,是否能够提交!
- 全部提交则事务组提交!有一个回滚标记则事务组回滚!
- 事务组执行操作之后,释放所有锁资源!
搭建分布式服务
下载官网提供的最新版的TM项目,修改配置文件(PS:由于官网的下载地址打不开,我们去GitHub上面下载例子:https://github.com/codingapi/txlcn-demo),参考txlcn-demo-tm工程,在我们之前的项目下面创建一个springboot项目叫txlcn-tm
参照官网修改配置文件,详细的TM配置请戳:https://www.txlcn.org/zh-cn/docs/setting/manager.html,开发阶段最好开启日志,并设置为debug等级,这样方便追踪排查问题
spring.application.name=txlcn-tm
server.port=7970
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=validate
# TM后台登陆密码
tx-lcn.manager.admin-key=123456
tx-lcn.manager.host=127.0.0.1
tx-lcn.manager.port=8070
# 开启日志,默认为false
tx-lcn.logger.enabled=true
tx-lcn.logger.driver-class-name=${spring.datasource.driver-class-name}
tx-lcn.logger.jdbc-url=${spring.datasource.url}
tx-lcn.logger.username=${spring.datasource.username}
tx-lcn.logger.password=${spring.datasource.password}logging.level.com.codingapi.txlcn=DEBUG
#redis 主机
spring.redis.host=127.0.0.1
#redis 端口
spring.redis.port=6379
#redis 密码
spring.redis.password=
在启动类添加注解 @EnableTransactionManagerServer
package cn.huanzi.qch.txlcn.tm;
import com.codingapi.txlcn.tm.config.EnableTransactionManagerServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableTransactionManagerServer
public class TxlcnTmApplication {
public static void main(String[] args) {
SpringApplication.run(TxlcnTmApplication.class, args);
}
}
我们的Redis服务运行起来,然后启动txlcn-tm,启动成功后访问tm后台管理系统,使用默认密码登录(可以配置登录密码),访问 http://127.0.0.1:7970/admin/index.html进入管理后台,默认密码是codingapi,我们这里配置了123456
启动TM之前记得先启动我们的Redis服务,到这里,我们的tm搭建成功,更多TM介绍,请看官网TM管理手册:https://www.txlcn.org/zh-cn/docs/manageradmin.html
测试
两个微服务,Server1和Server2
Server1启动类
启动类 注意:启动类必须添加@EnableDistributedTransaction注解 启动分布式事务
package com.order;
import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author huangfu
*/
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
@MapperScan("com.order.mapper")
@EnableDistributedTransaction
public class ServerOneApplication {
public static void main(String[] args) {
SpringApplication.run(ServerOneApplicatin.class);
}
}
注意:涉及到分布式事务的一定要添加 @LcnTransaction 注解
Server1Controller
package com.order.server.impl;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.order.client.ServerTwoClient;
import com.order.mapper.ServerOneMapper;
import com.order.server.ServerOneService;
import com.pojo.ServerOne;
import com.pojo.ServerTwo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author huangfu
*/
@Service
@SuppressWarnings("all")
public class ServerOneServiceImpl implements ServerOneService {
@Autowired
private ServerOneMapper serverOneMapper;
@Autowired
private ServerTwoClient serverTwoClient;
@Override
@LcnTransaction
@Transactional(rollbackFor = Exception.class)
public void insertData(ServerOne serverOne,String id) {
serverOneMapper.insertData(serverOne);
ServerTwo serverTwo = new ServerTwo(serverOne.getId(),serverOne.getName());
serverTwoClient.addData2(serverTwo);
if("1".equals(id)){
throw new RuntimeException("自定义异常");
}
System.out.println("---------------服务一执行完成---------------");
}
}
Server1利用Feign远程调用Server2
package com.order.client;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.pojo.ServerTwo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author huangfu
*/
@FeignClient(value = "server2")
public interface ServerTwoClient {
@RequestMapping(value = "/addData2",method = RequestMethod.POST)
public void addData2(@RequestBody ServerTwo serverTwo);
}
本文所有知识引用自:
https://www.oschina.net/p/tx-lcn?hmsr=aladdin1e1
https://www.cnblogs.com/huanzi-qch/p/11057974.html
https://blog.csdn.net/qq_37561309/article/details/101512691