seata集成

                                                          

 

 

1      引言

1.1       读者对象

1.2       预备知识

2      前置条件

2.1       适用场景

2.2       适用版本

2.3       下载地址

2.4       准备脚本

3      运维部署说明

3.1       配置registry.conf

3.2       配置file.conf

3.3       配置nacos-config.txt

3.4       执行nacos-config.sh

3.5       执行数据库脚本

3.6       启动seata

3.7       启动微服务

4      程序集成说明

4.1       程序集成参考工程

4.2       检查pom.xml引入包

4.3       检查数据源DruidConfig配置代理

4.4       检查registry.conf

4.5       检查配置bootstrap.properties的seata配置

4.6       检查配置nacos的seata配置

4.7       检查启动类Application初始化参数

4.8       使用分布式事务GlobalTransactional

第1章    引言

1.1  读者对象

本文描述了数字化运营平台分布式事务seata集成部署与集成,预期读者为运维人员,开发人员。

1.2  预备知识

相关人员在进行使用时,必须先具备springbootmysql,分布式事务相关知识。

 

 

 

 

 

 

第2章    前置条件

2.1  适用场景

Seata 是一款开源的分布式事务解决方案。Seata可集成nacos配置。

 

2.2  适用版本

Seata0.8.0版本。

 

2.3  下载地址

https://seata.io/zh-cn/blog/download.html

 

2.4  准备脚本

Ø  每个微服务数据库执行undo_log表脚本

Ø  db_store.sql数据库脚本

 

 

第3章    运维部署说明

3.1  配置registry.conf

配置seata-server\conf\ registry.confnacos地址

 

registry {

  # file nacos eurekarediszkconsuletcd3sofa

  type = "nacos"

 

  nacos {

    serverAddr = "10.0.4.79:8848"

    namespace = "public"

    cluster = "default"

  }

}

config {

  # filenacos apollozkconsuletcd3

  type = "nacos"

  nacos {

    serverAddr = "10.0.4.79:8848"

    namespace = "public"

    cluster = "default"

  }

}

 

 

è  注意:ip :portip :port格式

 

3.2  配置file.conf

配置seata-server\conf\ file.confseate启动地址列表

 

service {

  #vgroup->rgroup

  vgroup_mapping.my_test_tx_group = "default"

  #only support single node

  default.grouplist = "10.0.4.79: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"

}

 

 

è  注意:ip :portip :port格式

 

 

3.3  配置nacos-config.txt

配置seata-server\conf\ nacos-config.txt的参数

 

 

transport.type=TCP

transport.server=NIO

transport.heartbeat=true

transport.thread-factory.boss-thread-prefix=NettyBoss

transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker

transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler

transport.thread-factory.share-boss-worker=false

transport.thread-factory.client-selector-thread-prefix=NettyClientSelector

transport.thread-factory.client-selector-thread-size=1

transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread

transport.thread-factory.boss-thread-size=1

transport.thread-factory.worker-thread-size=8

transport.shutdown.wait=3

service.vgroup_mapping.module-service-consumer-seata=default

service.vgroup_mapping.module-service-provider-seata=default

service.enableDegrade=false

service.disable=false

service.max.commit.retry.timeout=-1

service.max.rollback.retry.timeout=-1

client.async.commit.buffer.limit=10000

client.lock.retry.internal=10

client.lock.retry.times=30

store.mode=db

store.file.dir=file_store/data

store.file.max-branch-session-size=16384

store.file.max-global-session-size=512

store.file.file-write-buffer-cache-size=16384

store.file.flush-disk-mode=async

store.file.session.reload.read_size=100

store.db.datasource=dbcp

store.db.db-type=mysql

store.db.driver-class-name=com.mysql.jdbc.Driver

store.db.url=jdbc:mysql://10.0.4.79:13306/seata?useUnicode=true

store.db.user=root

store.db.password=yda#121@11

store.db.min-conn=1

store.db.max-conn=3

store.db.global.table=global_table

store.db.branch.table=branch_table

store.db.query-limit=100

store.db.lock-table=lock_table

recovery.committing-retry-period=1000

recovery.asyn-committing-retry-period=1000

recovery.rollbacking-retry-period=1000

recovery.timeout-retry-period=1000

transaction.undo.data.validation=true

transaction.undo.log.serialization=jackson

transaction.undo.log.save.days=7

transaction.undo.log.delete.period=86400000

transaction.undo.log.table=undo_log

transport.serialization=seata

transport.compressor=none

metrics.enabled=false

metrics.registry-type=compact

metrics.exporter-list=prometheus

metrics.exporter-prometheus-port=9898

 

 

 

 

è  注意:service.vgroup_mapping.xxx=default中的xxxspringboot程序的seata.tx-service-groupvalue

 

3.4  执行nacos-config.sh

执行seata-server\conf\ nacos-config.sh的参数

./nacos-config.sh 10.0.4.79

 

 

è  注意:./nacos-config.sh  nacosip:port 格式

 

可以查看nacos的生产配置

 

 

 

è  注意:检查nacos配置中的store.db.password是正确

 

 

 

3.5  执行数据库脚本

执行seata-server\conf\db_store.sqldb_undo_log.sql

Ø  每个微服务的数据库(ocss)执行undo_log表脚本

Ø  db_store.sql数据库脚本

 

 

 

è  注意: 每个微服务数据库执行undo_log表脚本

 

 

 

3.6  启动seata

执行seata-server\bin\ seata-server.sh

nohup sh ./seata-server.sh -p 8091 -h 10.0.4.79 -m db -n 1 >log.out 2>1 &

 

 

è  注意:-p端口,-h地址

 

 

3.7  启动微服务

执行java -jar 命令,如下

java -jar module-service-consumer-6.0.0-SNAPSHOT.jar --spring.cloud.nacos.config.server-addr=10.0.4.79:8848

 

 

è  注意:通过spring.cloud.nacos.config.server-addr自动配置了seatanacos地址

 

第4章    程序集成说明

4.1  程序集成参考工程

参考工程template\

module-service-consumer

module-service-consumer

 

4.2  检查pom.xml引入包

检查pom.xml或者依赖的consumer-dependenceprovider-dependencepom.xml

 

<dependency>

            <groupId>com.alibaba.cloud</groupId>

            <artifactId>spring-cloud-alibaba-seata</artifactId>

        </dependency>

        <dependency>

         <groupId>io.seata</groupId>

         <artifactId>seata-spring-boot-starter</artifactId>

      </dependency>

        <dependency>

            <groupId>io.seata</groupId>

            <artifactId>seata-all</artifactId>

            <version>0.8.0</version>

        </dependency>

 

 

 

 

è  注意:注意必须是0.8.0版本

 

 

4.3  检查数据源DruidConfig配置代理

检查/com/yunbiaokj/module/service/provider/config/DruidConfig.java

 

@Bean

      public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {

          return new SqlSessionTemplate(sqlSessionFactory);

      }

   

   

      @Primary

      @Bean

      public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {

          return new DataSourceProxy(druidDataSource);

      }

 

      @Bean

      public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {

          MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();

          bean.setDataSource(dataSourceProxy);

          ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        // bean.setConfigLocation(resolver.getResource("classpath:mybatis-config.xml"));

        bean.setMapperLocations(resolver.getResources("classpath*:mapper/**/*Mapper.xml"));

 

          SqlSessionFactory factory = null;

          try {

              factory = bean.getObject();

          } catch (Exception e) {

              throw new RuntimeException(e);

          }

          return factory;

      }

 

 

 

è  注意:注意mapper文件必须能扫描到

 

4.4  检查registry.conf

检查/src/main/resources/ registry.conf

 

registry {

  # file nacos eurekarediszkconsuletcd3sofa

  type = "nacos"

 

  nacos {

    #serverAddr = "10.0.4.79:8848"

    namespace = "public"

    cluster = "default"

  }

}

config {

  # filenacos apollozkconsuletcd3

  type = "nacos"

  nacos {

    #serverAddr = "10.0.4.79:8848"

    namespace = "public"

    cluster = "default"

  }

}

 

 

 

è 注意:#serverAddr必须注释掉

 

4.5  检查配置bootstrap.propertiesseata配置

配置/src/main/resources/ bootstrap.propertiesseata.tx-service-group

 

 

spring.cloud.alibaba.seata.tx-service-group=module-service-consumer-seata 

 

 

è  注意:配置seata.tx-service-group

 

 

4.6  检查配置nacosseata配置

配置/src/main/resources/ bootstrap.propertiesseata.tx-service-group

 

 

 

è  注意:配置dataIdservice.vgroup_mapping.xxx中的xxxbootstrap.propertiesseata.tx-service-group的值

 

 

4.7  检查启动类Application初始化参数

检查com/yunbiaokj/module/service/provider/ServiceProviderApplication.java

 

 

@SpringBootApplication

@EnableDiscoveryClient

@ComponentScan(basePackages = {"com.yunbiaokj.module.service.consumer", "com.yunbiaokj.common.mq", "com.yunbiaokj.common.session"})

public class ServiceConsumerApplication {

 

    public static void main(String[] args) throws IOException {

      initCommand( args);

        SpringApplication.run(ServiceConsumerApplication.class, args);

    }

   

    private static void initCommand(String[] args) throws IOException{

      setProperty(args,"serverAddr","spring.cloud.nacos.config.server-addr");

      setProperty(args,"namespace","spring.cloud.nacos.discovery.namespace");

  }

   

    private static void  setProperty(String[] args,String propertyKey,String commandKey) throws IOException{

      Optional<String> serverAddrValueOptional = Arrays.stream(args).filter(str -> str.contains(commandKey) ).findFirst();

      System.setProperty(propertyKey, serverAddrValueOptional.isPresent()?serverAddrValueOptional.get().split("=")[1]:getPropertiesValue(commandKey));

    }

 

  private static String getPropertiesValue(String key) throws IOException{

       return PropertiesLoaderUtils.loadAllProperties("bootstrap.properties").getProperty(key);

  }

 

}

}

 

 

 

 

è  注意:注意必须通过initCommand()方法进行初始化

 

 

4.8  使用分布式事务GlobalTransactional

检查消费者添加GlobalTransactional注解

 

/com/yunbiaokj/module/service/consumer/controller/SeataController.java例子如下

@RequestMapping(value = "/module/service") 

@RestController

public class SeataController {

    @Autowired

    private  RestTemplate restTemplate;

   

 

    @GlobalTransactional(timeoutMills = 300000, name = "SeataController-seata")

    @Transactional(rollbackFor = Exception.class)

    @RequestMapping(value = "/seata/{id}", method = RequestMethod.GET)

    public String seata(@PathVariable Long id) {

      String r1 = restTemplate.getForObject("http://module-service-provider/module/seata/del1/"+(id-1) ,

              String.class);

      System.out.println("r1 " +r1 );

     

      String r2 =restTemplate.getForObject("http://module-service-provider/module/seata/del2/"+id ,

              String.class);

          System.out.println("r2 " +r2 );

        return r1 +" " + r2;

    }

 

}

 

 

 

 

 

è  注意:注意必须GlobalTransactional注解

 

检查消费者添加RootContext.getXID()

/com/yunbiaokj/module/service/provider/controller/SeataController.java例子如下

 

 

@RequestMapping(value = "/module/seata")

@RestController

public class SeataController {

  @Autowired

  private HotelService hotelService;

    //@Transactional // 开启新事物

  @GetMapping("/del1/{id}")

  public String seata(@PathVariable(name="id") Long id) throws Exception {

      System.out.println("[seata] 当前 XID: "+ RootContext.getXID());

      System.out.println("SeataController seata  id " +id);

      //return hotelService.selectByCityId(id);

      if (hotelService.selectByCityId(id)==null) {

            throw new Exception("数据不存在");

      }

      hotelService.deleteByCityId(id);

      return id +" is delete";

  }

 

    //@Transactional // 开启新事物

    @GetMapping("/del2/{id}")

  public String seata2(@PathVariable(name="id") Long id) throws Exception{

      System.out.println("[seata2] 当前 XID: "+ RootContext.getXID());

      System.out.println("SeataController seata2  id " +id);

      if (hotelService.selectByCityId(id)==null) {

            throw new Exception("数据不存在");

      }

      hotelService.deleteByCityId(id);

      return id +" is delete";

  }

}

 

  

 

 

 

 

è  注意:注意消费者能否获取RootContext.getXID(),并且能抛出throws Exception才能实现分布式事务