实战项目中整合Seata编码实践
第一步,创建 undo_log
表。
在需要处理分布式事务的微服务实例下的数据库中创建 undo_log
表,实战项目中涉及分布式事务处理的微服务实例有 订单微服务、购物车微服务 和 商品微服务,因此要在 newbee_mall_cloud_order_db
数据库、newbee_mall_cloud_cart_db
数据库和 newbee_mall_cloud_goods_db
数据库中依次创建 undo_log
表。
第二步,添加 Seata
依赖。
依次打开 newbee-mall-cloud-order-web
、newbee-mall-cloud-shop-cart-web
和 newbee-mall-cloud-goods-web
3 个项目中的 pom.xml
文件,在 dependencies
节点下新增 Seata
的依赖项,配置代码如下:
<!-- Seata 依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
第三步,添加 Seata
配置项。
依次打开 newbee-mall-cloud-order-web
、newbee-mall-cloud-shop-cart-web
和 newbee-mall-cloud-goods-web
3 个项目中的 application.properties
配置文件并进行修改,最终增加的配置项代码如下:
seata.enabled=true
#3个不同的微服务被命名为不同的名称,如goods-server、order-server、shopcart-server
seata.application-id=order-server
#事务分组配置
seata.tx-service-group=newbee_cloud_save_order_group
service.vgroupMapping.newbee_cloud_save_order_group=default
#连接Nacos服务中心的配置信息
seata.registry.type=nacos
seata.registry.nacos.application=seata-server
seata.registry.nacos.server-addr=127.0.0.1:8848
seata.registry.nacos.username=nacos
seata.registry.nacos.password=nacos
seata.registry.nacos.group=DEFAULT_GROUP
seata.registry.nacos.cluster=default
在 3 个项目的配置文件中依次添加上述配置代码即可,其他配置项可以不用配置,使用 Seata
的默认值即可。
第四步,添加 Seata
数据源代理。
依次打开 newbee-mall-cloud-order-web
、newbee-mall-cloud-shop-cart-web
和 newbee-mall-cloud-goods-web
3 个项目中的 config
包,新增 SeataProxyConfiguration
类,代码如下:
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
@Configuration
public class SeataProxyConfiguration {
//创建 Druid 数据源
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
//创建 DataSource 数据源代理
@Bean("dataSource")
@Primary
public DataSource dataSourceDelegation(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
/*
* 解决 druid 日志报错; discard long time none received connection:xxx
*/
@PostConstruct
public void setProperties() {
System.setProperty("druid.mysql.usePingMethod", "false");
}
}
第五步,添加 @GlobalTransactional
注解。
打开 newbee-mall-cloud-order-web
项目中的 ltd.order.cloud.newbee.service.impl.NewBeeMallOrderServiceImpl
类,在 saveOrder()
方法上添加 @GlobalTransactional
注解,代码修改如下:
@Override
@Transactional
//加上这个注解,开启 Seata 分布式事务
@GlobalTransactional
public String saveOrder(Long mallUserId, MallUserAddress address, List<Long> cartItemIds) {
//省略部分代码
}
saveOrder()
方法是一个涉及分布式事务的方法,在这个方法中会调用其他微服务来共同完成 “下单” 的流程,进而会操作 3 个独立的数据库。在这个方法上添加的 @GlobalTransactional
注解是全局事务注解,作用是开启全局事务。当执行到 saveOrder()
方法时,会自动开启全局事务。如果该方法中的代码逻辑都正常执行,则进行全局事务的 Commit
操作;如果该方法中抛出异常,则进行 RollBack
操作。在购物车微服务和商品微服务的分支事务中不需要添加这个注解。