点点我:JAVA互联网架构师专题/分布式/高并发/微服务 提取马:xb2kjava
1.1 环境准备 1)指定nacos做为配置中心和注册中心 修改registry.conf文件 V(cmL46679910)mysql
注意:客户端配置registry.conf使用nacos时也要注意group要和seata server中的 group一致,默认group是"DEFAULT_GROUP"redis
2)同步seata server的配置到nacosspring
获取/seata/script/config-center/config.txt,修改配置信息sql
配置事务分组, 要与客户端配置的事务分组一致 (客户端properties配置:spring.cloud.alibaba.seata.tx‐servicegroup= my_test_tx_group)shell
配置参数同步到Nacos数据库
shell: sh ${SEATAPATH}/script/config‐center/nacos/nacos‐config.sh ‐h localhost ‐p 8848 ‐g SEATA_GROUP ‐t 5a3c7d6c‐f497‐4d68‐a71a‐2e5e3340b3ca 参数说明: -h: host,默认值 localhost交流V(cmL46679910) -p: port,默认值 8848 -g: 配置分组,默认值为 'SEATA_GROUP' -t: 租户信息,对应 Nacos 的命名空间ID字段, 默认值为空 ''apache
3) 启动Seata Servermarkdown
启动Seata Server命令 bin/seata‐server.sh 启动成功,默认端口8091session
在注册中心中能够查看到seata-server注册成功
业务场景:
用户下单,整个业务逻辑由三个微服务构成: 仓储服务:对给定的商品扣除库存数量。 订单服务:根据采购需求建立订单。 账户服务:从用户账户中扣除余额。 点点我:JAVA互联网架构师专题/分布式/高并发/微服务 提取马:xb2k
环境准备: seata: v1.4.0 spring cloud&spring cloud alibaba: 1 <spring‐cloud.version>Greenwich.SR3</spring‐cloud.version> 2 <spring‐cloud‐alibaba.version>2.1.1.RELEASE</spring‐cloud‐alibaba.version> 注意版本选择问题: spring cloud alibaba 2.1.2 及其以上版本使用seata1.4.0会出现以下异常 (支持seata 1.3.0)
2.1 导入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring‐cloud‐starter‐alibaba‐seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata‐all</artifactId>
</exclusion>
</exclusions>
</dependency>
**交流V**(**cmL46679910**)
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata‐all</artifactId>
<version>1.4.0</version>
</dependency>
<!‐‐nacos 注册中心‐‐>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring‐cloud‐starter‐alibaba‐nacos‐discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring‐cloud‐starter‐openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid‐spring‐boot‐starter</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql‐connector‐java</artifactId>
<scope>runtime</scope>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis‐spring‐boot‐starter</artifactId>
<version>2.1.1</version>
</dependency>
复制代码
2.2 微服务对应数据库中添加undo_log表
```CREATE TABLE undo_log
( id
bigint(20) NOT NULL AUTO_INCREMENT, branch_id
bigint(20) NOT NULL, xid
varchar(100) NOT NULL, context
varchar(128) NOT NULL, rollback_info
longblob NOT NULL, log_status
int(11) NOT NULL,交流V(cmL46679910) log_created
datetime NOT NULL, log_modified
datetime NOT NULL, PRIMARY KEY (id
), UNIQUE KEY ux_undo_log
(xid
,branch_id
) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2.3 微服务须要使用seata DataSourceProxy代理本身的数据源
复制代码
/**
*/ @Configuration @MapperScan("com.tuling.datasource.mapper") public class MybatisConfig {
/**
/ @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource druidDataSource() { DruidDataSource druidDataSource = new DruidDataSource(); return druidDataSource; } 交流V(cmL46679910) /*
*/ @Primary @Bean("dataSource") public DataSourceProxy dataSourceProxy(DataSource druidDataSource) { return new DataSourceProxy(druidDataSource); }
@Bean(name = "sqlSessionFactory") public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourcePro xy) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); //设置代理数据源 factoryBean.setDataSource(dataSourceProxy); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); factoryBean.setMapperLocations(resolver.getResources("classpath*:mybatis/**/ *‐mapper.xml"));
org.apache.ibatis.session.Configuration configuration=new org.apache.ibatis.session.Configuration(); //使用jdbc的getGeneratedKeys获取数据库自增主键值 configuration.setUseGeneratedKeys(true); //使用列别名替换列名 configuration.setUseColumnLabel(true); //自动使用驼峰命名属性映射字段,如userId ‐‐‐> user_id configuration.setMapUnderscoreToCamelCase(true); factoryBean.setConfiguration(configuration);
return factoryBean.getObject(); }
} 注意: 启动类上须要排除DataSourceAutoConfiguration,不然会出现循环依赖的问题
启动类排除DataSourceAutoConfiguration.class
@SpringBootApplication(scanBasePackages = "com.tuling",exclude = DataSourceAut oConfiguration.class) public class AccountServiceApplication {交流V(cmL46679910)
public static void main(String[] args) { SpringApplication.run(AccountServiceApplication.class, args); }
}
4. 添加seata的配置
)将registry.conf文件拷贝到resources目录下,指定注册中心和配置中心都是nacos
```registry {
# file 、nacos 、eureka、redis、zk、consul、etcd三、sofa
type = "nacos"
nacos {
serverAddr = "192.168.65.232:8848"
namespace = ""
cluster = "default"
group = "SEATA_GROUP"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd三、springCloudConfig
type = "nacos"**交流V**(**cmL46679910**)
nacos {
serverAddr = "192.168.65.232:8848"
namespace = "29ccf18e‐e559‐4a01‐b5d4‐61bad4a89ffd"
group = "SEATA_GROUP"
}
}
复制代码
在 org.springframework.cloud:spring-cloud-starter-alibaba-seata
的 org.springframework.cloud.alibaba.seata.GlobalTransactionAutoConfiguration
类中,默认会使用 ${spring.application.name}-seata-service-group
做为服务名注 册到 Seata Server上,若是和service.vgroup_mapping配置不一致,会提示 no available server to connect
错误 也能够经过配置 spring.cloud.alibaba.seata.tx-service-group
修改后缀,可是必须 和file.conf
中的配置保持一致
2)在yml中指定事务分组(和配置中心的service.vgroup_mapping 配置一一对应)
application:
name: account‐service
cloud:
nacos:
discovery:
server‐addr: 127.0.0.1:8848
alibaba:
seata:
tx‐service‐group:
my_test_tx_group # seata 服务事务分组
复制代码
参考源码: io.seata.core.rpc.netty.NettyClientChannelManager#getAvailServerList 》NacosRegistryServiceImpl#lookup 》String clusterName = getServiceGroup(key); #获取seata server集群名称 》List firstAllInstances = getNamingInstance().getAllInstances(getServiceName(), getServiceGroup(), clusters)
spring cloud alibaba 2.1.4 以后支持yml中配置seata属性,能够用来替换registry.conf文件
配置支持实如今seata-spring-boot-starter.jar中,也能够引入依赖 1 2 io.seata 3 seata‐spring‐boot‐starter 4 1.4.0 5
在yml中配置
# seata 服务分组,要与服务端nacos‐config.txt中service.vgroup_mapping的后缀对应
tx‐service‐group: my_test_tx_group
registry:
# 指定nacos做为注册中心
type: nacos
nacos:
server‐addr: 127.0.0.1:8848
namespace: ""
group: SEATA_GROUP
config:
# 指定nacos做为配置中心
type: nacos
nacos:
server‐addr: 127.0.0.1:8848
namespace: "54433b62‐df64‐40f1‐9527‐c907219fc17f"
group: SEATA_GROUP
复制代码
3) 在事务发起者中添加@GlobalTransactional注解 核心代码
//@Transactional
@GlobalTransactional(name="createOrder")
public Order saveOrder(OrderVo orderVo){
log.info("=============用户下单=================");
log.info("当前 XID: {}", RootContext.getXID());
// 保存订单
Order order = new Order();
order.setUserId(orderVo.getUserId());
order.setCommodityCode(orderVo.getCommodityCode());
order.setCount(orderVo.getCount());
order.setMoney(orderVo.getMoney());**交流V**(**cmL46679910**)
order.setStatus(OrderStatus.INIT.getValue());**交流V**(**cmL46679910**)
Integer saveOrderRecord = orderMapper.insert(order);
log.info("保存订单{}", **交流V**(**cmL46679910**)saveOrderRecord > 0 ? "成功" : "失败");
//扣减库存
storageFeignService.deduct(orderVo.getCommodityCode(),orderVo.getCount());
//扣减余额
accountFeignService.debit(orderVo.getUserId(),orderVo.getMoney());
//更新订单
Integer updateOrderRecord = orderMapper.updateOrderStatus(order.getId(),Orde
rStatus.SUCCESS.getValue());
log.info("更新订单id:{} {}", order.getId(), updateOrderRecord > 0 ? "成功" :
"失败");
return order;
}
复制代码