1.Seataサーバーを起動します
1.1環境の準備
1)構成センターおよび登録センターとしてnacosを指定します
Registry.confファイルを変更します
注:クライアントがnacosを使用するようにregistry.confを構成する場合、グループはseataサーバーのグループと同じである必要があることに注意してください。デフォルトのグループは「DEFAULT_GROUP」です。
2)seataサーバーの構成をnacosに同期します
/seata/script/config-center/config.txtを取得し、構成情報を変更します
クライアントによって構成されたトランザクショングループと一致するようにトランザクショングループを構成し
ます(クライアントプロパティの構成:spring.cloud.alibaba.seata.tx-service-group = my_test_tx_group)
構成パラメーターはNacos
シェルに同期されます。
sh ${SEATAPATH}/script/config-center/nacos/nacos-config.sh -h localhost -p 8848 -g SEATA_GROUP -t 5a3c7d6c-f497-4d68-a71a-2e5e3340b3ca
パラメータの説明:
-h:ホスト、デフォルト値はlocalhost
-p:ポート、デフォルト値は8848
-g:構成グループ、デフォルト値は'SEATA_GROUP'
-t:テナント情報。Nacos名前空間IDフィールドに対応します。デフォルト値は空です''
3)Seataサーバーを起動します
Seataサーバーコマンドを開始します
bin/seata-server.sh
正常に開始されました。デフォルトのポート8091
登録センターでは、seata-server登録が成功していることがわかります。
2.SeataがSpringCloudマイクロサービスに統合する方法
ビジネスシーン:
ユーザーが注文すると、ビジネスロジック全体が3つのマイクロサービスで構成されます。
倉庫保管サービス:特定の商品の在庫数量を差し引きます。
注文サービス:購入ニーズに基づいて注文を作成します。
アカウントサービス:ユーザーアカウントからの借方残高。
環境の準備:
seata:v1.4.0
spring cloud&spring cloud alibaba:
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
<spring-cloud-alibaba.version>2.1.1.RELEASE</spring-cloud-alibaba.version>
バージョン選択の問題に注意して
ください。SpringCloudAlibaba2.1.2以降では、seata1.4.0(seata 1.3.0をサポート)を使用する場合、次の例外が発生します。
2.1依存関係のインポート
<!-- seata-->
<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>
<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,
`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マイクロサービスは、独自のデータソースをプロキシするためにseataDataSourceProxyを使用する必要があります
/**
* 需要用到分布式事务的微服务都需要使用seata DataSourceProxy代理自己的数据源
*/
@Configuration
@MapperScan("com.cry.datasource.mapper")
public class MybatisConfig {
/**
* 从配置文件获取属性构造datasource,注意前缀,这里用的是druid,根据自己情况配置,
* 原生datasource前缀取"spring.datasource"
*
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
/**
* 构造datasource代理对象,替换原来的datasource
* @param druidDataSource
* @return
*/
@Primary
@Bean("dataSource")
public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) 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.cry",exclude = DataSourceAutoConfiguration.class)
public class AccountServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AccountServiceApplication.class, args);
}
}
4.シートの構成を追加します
1)registry.confファイルをresourcesディレクトリーにコピーし、レジストリーと構成センターが両方ともnacosであることを指定します
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "192.168.65.232:8848"
namespace = ""
cluster = "default"
group = "SEATA_GROUP"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3、springCloudConfig
type = "nacos"
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
でサービス名として構成と矛盾する場合はno available server to connect
、
エラーが表示されます。spring.cloud.alibaba.seata.tx-service-group
構成を通じてサフィックスを変更することもできますが、file.conf
一貫している必要があります。の構成で
2)トランザクショングループをymlで指定します(構成センターのservice.vgroup_mapping構成との1対1の対応)
spring:
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);#Getシートサーバークラスター名
》 List firstAllInstances = getNamingInstance()。getAllInstances(getServiceName()、 getServiceGroup()、クラスター)
Spring Cloud alibaba 2.1.4以降は、ymlでのseataプロパティの構成をサポートします。これは、registry.confファイルを置き換えるために使用できます
。構成サポートはseata-spring-boot-starter.jarに実装され、依存関係も可能です。紹介される
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
ymlで構成する
seata:
# 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アノテーションをトランザクションイニシエーターに追加します
コアコード
@Override
//@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());
order.setStatus(OrderStatus.INIT.getValue());
Integer saveOrderRecord = orderMapper.insert(order);
log.info("保存订单{}", saveOrderRecord > 0 ? "成功" : "失败");
//扣减库存
storageFeignService.deduct(orderVo.getCommodityCode(),orderVo.getCount());
//扣减余额
accountFeignService.debit(orderVo.getUserId(),orderVo.getMoney());
//更新订单
Integer updateOrderRecord = orderMapper.updateOrderStatus(order.getId(),OrderStatus.SUCCESS.getValue());
log.info("更新订单id:{} {}", order.getId(), updateOrderRecord > 0 ? "成功" : "失败");
return order;
}
4)分散トランザクションが有効かどうかをテストします
ユーザーによる注文の口座残高が不足している場合、在庫はロールバックされますか?