springcloud+eureka+mybatis+seata分布式事务部署

seata服务端和spring源码项目地址(很详细的资源-包括建表等等):完整项目地址

服务调用关系图springcloud+eureka+mybatis+seata分布式事务部署_第1张图片
那么现在开始搭建分布式事务吧,本文章是和上面项目地址里面的项目所进行对应的,建议读者对seata有所了解,这样跟着步骤走,不仅能加深对分布式事务的理解,同时也能体会到分布式事务的简单与强大!!!

1:搭建seata服务端:

  • 下载seata-server
  • springcloud+eureka+mybatis+seata分布式事务部署_第2张图片
  • 修改file.conf ( /conf/file.conf )
    springcloud+eureka+mybatis+seata分布式事务部署_第3张图片
    springcloud+eureka+mybatis+seata分布式事务部署_第4张图片
    -修改registry.conf (/conf/registry.conf)
    springcloud+eureka+mybatis+seata分布式事务部署_第5张图片

2:启动eureka,并启动seata-server(window 在/bin/seata-server.bat)

3:建立数据库
需要建立4个微服务的数据库和一个seata-server数据库,并且每个rm微服务参与者的数据库里面都必须有undo_log表用来存当前事务的回滚数据,,建数据库的sql在项目里面有
springcloud+eureka+mybatis+seata分布式事务部署_第6张图片
springcloud+eureka+mybatis+seata分布式事务部署_第7张图片
4:在原有项目基础上改造微服务

  • 分布式事务参与者都要在resources里面加file.conf和registry.conf文件,并且都要加一个代理数据源注册进spring中
  • file.conf
transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  # the client batch send request enable
  enableClientBatchSendRequest = true
  #thread factory for netty
  threadFactory {
    bossThreadPrefix = "NettyBoss"
    workerThreadPrefix = "NettyServerNIOWorker"
    serverExecutorThread-prefix = "NettyServerBizHandler"
    shareBossWorker = false
    clientSelectorThreadPrefix = "NettyClientSelector"
    clientSelectorThreadSize = 1
    clientWorkerThreadPrefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    bossThreadSize = 1
    #auto default pin or 8
    workerThreadSize = "default"
  }
  shutdown {
    # when destroy server, wait seconds
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
  #transaction service group mapping
  vgroup_mapping.seata-test-server = "seata-test-server" #修改事务组名称为:fsp_tx_group,和客户端自定义的名称对应
  #only support when registry.type=file, please don't set multiple addresses
  seata-test-server.grouplist = "127.0.0.1:8091"
  #degrade, current not support
  enableDegrade = false
  #disable seata
  disableGlobalTransaction = false
}

client {
  rm {
    asyncCommitBufferLimit = 10000
    lock {
      retryInterval = 10
      retryTimes = 30
      retryPolicyBranchRollbackOnConflict = true
    }
    reportRetryCount = 5
    tableMetaCheckEnable = false
    reportSuccessEnable = false
  }
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
  }
  undo {
    dataValidation = true
    logSerialization = "jackson"
    logTable = "undo_log"
  }
  log {
    exceptionRate = 100
  }
}

-registry.conf

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "eureka"

  nacos {
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
  }
  eureka {
    serviceUrl = "http://127.0.0.1:7001/eureka"
    application = "seata-test-server"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = "0"
    password = ""
    cluster = "default"
    timeout = "0"
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
    username = ""
    password = ""
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3、springCloudConfig
  type = "file"

  nacos {
    serverAddr = "localhost"
    namespace = ""
    group = "SEATA_GROUP"
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
    app.id = "seata-server"
    apollo.meta = "http://192.168.1.204:8801"
    namespace = "application"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
    username = ""
    password = ""
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}

-添加代理数据源

package com.atguigu.springcloud.config;

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
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 org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.web.client.RestTemplate;

import javax.sql.DataSource;

/**
 * 数据源代理
 * @author wangzhongxiang
 */
@Configuration
public class DataSourceConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Primary
    @Bean("dataSource")
    public DataSourceProxy dataSource(DataSource druidDataSource){
        return new DataSourceProxy(druidDataSource);
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy)throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSourceProxy);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:/mapper/*.xml"));
        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
        return sqlSessionFactoryBean.getObject();
    }

}
  • 每个分布式事务参与者都要修改配置文件
spring:
  application:
    name: cloud-payment-service8004
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://127.0.0.1:3306/my_data8004?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: daibin
  #分布式事务
  cloud:
    alibaba:
      seata:
        tx-service-group: seata-test-server

5:在触发点加一个全局分布式事务注解
我这里的触发点是8001的这个微服务

package com.atguigu.springcloud.service.impl;

import com.atguigu.springcloud.dao.PaymentDao;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@Service
public class PaymentServiceImpl implements PaymentService {
    @Resource
    private PaymentDao paymentDao;
    @Autowired
    private RestTemplate restTemplate;

    @Override
    //全局事务注解
    @GlobalTransactional(name = "seata-test-server", rollbackFor = Exception.class)
    public int create(Payment payment) {
        int id=paymentDao.create(payment);
        if(payment.getSerial().equals("第8001调")){
            int i=1/0;
        }
        if(payment.getSerial().equals("第8001调延时")){
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        String url8002="http://127.0.0.1:8002/payment/create";
        String url8004="http://127.0.0.1:8004/payment/create";
        restTemplate.postForObject(url8002,payment,Object.class);
        restTemplate.postForObject(url8004,payment,Object.class);
        return id;
    }

    @Override
    public Payment getPaymentById(Integer id) {
        return paymentDao.getPaymentById(id);
    }
}

6:启动项目测试

  • 先启动eureka
  • 再启动seata-server
  • 再把各个微服务启起来
  • 测试
  • 会发现要么全部成功,要么全部失败

你可能感兴趣的:(JAVA)