基本介绍
- 什么是分布式事务
指一次大的操作由不同的小操作组成的,这些小的操作分布在不同的服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败。从本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
- 为什么要使用分布式事务
在微服务独立数据源的思想,每一个微服务都有一个或者多个数据源,虽然单机单库事务已经非常成熟,但是由于网路延迟和不可靠的客观因素,分布式事务到现在也还没有成熟的方案,对于中大型网站,特别是涉及到交易的网站,一旦将服务拆分微服务,分布式事务一定是绕不开的一个组件,通常解决分布式事务问
- seata 分布式事务
Seata
是阿里开源的一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
Seata
目标打造一站式的分布事务的解决方案,最终会提供四种事务模式:
AT 模式:参见(《Seata AT 模式》 (opens new window))文档
TCC 模式:参见(《Seata TCC 模式》 (opens new window))文档
Saga 模式:参见(《SEATA Saga 模式》 (opens new window))文档
XA 模式:正在开发中... 目前使用的流行度情况是:AT
> TCC
> Saga
。因此,我们在学习Seata
的时候,可以花更多精力在AT
模式上,最好搞懂背后的实现原理,毕竟分布式事务涉及到数据的正确性,出问题需要快速排查定位并解决。
一、下载安全seata
二、配置seata服务器相关参数
例如:
开发环境
mysql配置
store.db.url=jdbc:mysql://xxx.xxxx.0.48:3306/xxxxxx?useUnicode=true
config配置
sh nacos-config.sh -h xxx.xxxx.0.56 -p 8848 -g SEATA_GROUP
启动配置
nohup sh seata-server.sh -p 8091 -h 10.10.0.63 &
regist.cof 配置修改namespace
nacos {
application = "seata-server"
serverAddr = "xxx.xxxx.0.56:8848"
group = "SEATA_GROUP"
namespace = "ns_test"
cluster = "default"
username = "nacos"
password = "nacos"
}
yml配置
# seata配置
seata:
# 默认关闭,如需启用spring.datasource.dynami.seata需要同时开启
enabled: true
# Seata 应用编号,默认为 ${spring.application.name}
application-id: ${spring.application.name}
# Seata 事务组编号,用于 TC 集群名
tx-service-group: ${spring.application.name}-group
# 关闭自动代理
enable-auto-data-source-proxy: false
# 服务配置项
service:
# 虚拟组和分组的映射
vgroup-mapping:
*******-group: default
config:
type: nacos
nacos:
serverAddr: *******:8848
group: SEATA_GROUP
namespace:
registry:
type: nacos
nacos:
application: seata-server
server-addr: *******0.56:8848
namespace:
#必须和注册中心中命名空间保持一致
被调用方
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int insertSysExportRecord(SysExportRecord sysExportRecord)
{
System.out.println("当前 XID: "+ RootContext.getXID());
String id = UUID.randomUUID().toString().replace("-","");
sysExportRecord.setId(id);
sysExportRecord.setCreateBy(SecurityUtils.getUserId().toString());
sysExportRecord.setCreateTime(DateUtils.getNowDate());
return sysExportRecordMapper.insertSysExportRecord(sysExportRecord);
}
调用方
@PostMapping
@Transactional
@GlobalTransactional(rollbackFor = RuntimeException.class) // 重点 第一个开启事务的需要添加seata全局事务注解
public AjaxResult add(@RequestBody TCostingSpecialityBasics tCostingSpecialityBasics)
{
int a = tCostingSpecialityBasicsService.insertTCostingSpecialityBasics(tCostingSpecialityBasics);
System.out.println("当前 XID: "+ RootContext.getXID());
SysExportRecord exportRecord = new SysExportRecord();
exportRecord.setBusinessTabname("t_purchase_apply");
exportRecord.setBusinessTabid("123456");
exportRecord.setExportNum(Long.valueOf(1));
try
{
//List<String> list = new ArrayList<String>();
//list.get(1);
}catch (Exception e) {
throw new RuntimeException("异常处理");
}
remoteExportRecordService.addExopertRecord(exportRecord);
return toAjax( a);
}