分布式事务解决方案 - Seata 使用样例
分布式事务解决方案 - Seata 使用样例
Seata Server端环境准备
(1)从官网上下载seata server端的程序包
下载地址:https://github.com/seata/seata/releases
(2)修改配置
我们是基于file的方式启动注册和承载配置的
打开conf/file.conf文件
修改service 节点目录内容如下:
service {
#vgroup->rgroup
vgroup_mapping.my_test_tx_group = "default"
#only support single node
default.grouplist = "127.0.0.1:8091"
#degrade current not support
enableDegrade = false
#disable
disable = false
#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
max.commit.retry.timeout = "-1"
max.rollback.retry.timeout = "-1"
}
说明:需要修改default.grouplist = “127.0.0.1:8091”,将该值设置为seata server向外提供服务ip及端口(或域名+端口)
(4)启动server
到bin目录下执行脚本启动seata server端,注:windows下执行seata-server.bat
启动;linux下执行seata-server.sh
启动
2.4 项目集成seata
2.4.1 创建日志表undo_log
分别在leadnews_article、leadnews_user、leadnews_wemedia三个库中都创建undo_log表
2.4.2 导入依赖包
因为有多个工程都需要引入seata,所以新建一个工程heima-leadnews-seata专门来处理分布式事务
<dependencies>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-common</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>0.9.0</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
</dependencies>
2.4.3 创建代理数据源
(1)因为多个工程都需要依赖与seata,所以在heima-leadnews-seata模块下创建seata的配置类
package com.heima.seata.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import io.seata.rm.datasource.DataSourceProxy;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@EnableConfigurationProperties({MybatisPlusProperties.class})
public class DataSourcesProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
return new DruidDataSource();
}
//创建代理数据源
@Primary//@Primary标识必须配置在代码数据源上,否则本地事务失效
@Bean
public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
private MybatisPlusProperties properties;
public DataSourcesProxyConfig(MybatisPlusProperties properties) {
this.properties = properties;
}
//替换SqlSessionFactory的DataSource
@Bean
public MybatisSqlSessionFactoryBean sqlSessionFactory(DataSourceProxy dataSourceProxy, PaginationInterceptor paginationInterceptor) throws Exception {
// 这里必须用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否则 MyBatisPlus 不会生效
MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
mybatisSqlSessionFactoryBean.setDataSource(dataSourceProxy);
mybatisSqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
mybatisSqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath*:/mapper/*.xml"));
MybatisConfiguration configuration = this.properties.getConfiguration();
if(configuration == null){
configuration = new MybatisConfiguration();
}
mybatisSqlSessionFactoryBean.setConfiguration(configuration);
//设置分页
Interceptor[] plugins = {paginationInterceptor};
mybatisSqlSessionFactoryBean.setPlugins(plugins);
return mybatisSqlSessionFactoryBean;
}
}
(2)分别在heima-leadnews-article、heima-leadnews-user、heima-leadnews-wemedia引入heima-leadnews-seata工程,并且添加一下配置类:
@Configuration
@ComponentScan("com.heima.seata.config")
public class SeataConfig {
}
2.4.4 配置seata-server链接和注册中心信息
修改注册中心配置,在每个项目中必须按照下方要求来
将配置文件file.conf和配置文件register.conf放到每个需要参与分布式事务项目的resources中。
- file.conf中的service.default.grouplist修改成seata-server的IP地址file.conf中的
- service.vgroup_mapping.xxx改成vgroup_mapping.#{spring.application.name}_tx_group = “default”
特别注意:#{spring.application.name}
是一个变量,指的是该项目的名称
如自媒体微服务名称的项目名称如下:
那么其配置就是vgroup_mapping.leadnews-wemedia_tx_group = "default"
其他项目也是这么依次配置
2.4.5 指定事务分组
分别在heima-leadnews-article、heima-leadnews-user、heima-leadnews-wemedia微服务的application.yml文件中添加如下配置:
spring:
cloud:
alibaba:
seata:
tx-service-group: ${spring.application.name}_tx_group
2.4.6 在分布式事务控制方法上添加注解@GlobalTransactional
在ApUserRealnameServiceImpl类的updateStatusById方法上加上@GlobalTransactional
注解
2.4.7 启动seata-server
运行:/seata/bin/seata-server.bat
2.4.8 测试
(1)功能测试,看功能能否正常执行。
(2)异常测试,我们在方法中添加int x=1/0
,看认证信息和自媒体用户是否能够回滚。