分布式事務解決方案 - Seata 使用樣例


分布式事務解決方案 - Seata 使用樣例

Seata Server端環境准備

(1)從官網上下載seata server端的程序包

下載地址:https://github.com/seata/seata/releases

(2)修改配置

我們是基於file的方式啟動注冊和承載配置的

1612147785304

打開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}是一個變量,指的是該項目的名稱

如自媒體微服務名稱的項目名稱如下:

1612147815398

那么其配置就是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

1612147833840

2.4.8 測試

(1)功能測試,看功能能否正常執行。

(2)異常測試,我們在方法中添加int x=1/0 ,看認證信息和自媒體用戶是否能夠回滾。

1612147850821


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM