由于目前互联网企业的兴起,越来越多的企业开始采用微服务架构模式。微服务架构模式的确提升后台服务的性能,保证服务的高可用等优点,但是同时也带来了一个问题,即如何保证数据的一致性、操作原子性,即分布式事务。目前,互联网主要有2PC,3PC,TCC,事务性事务方式。 今天就主要介绍阿里旗下的分布式事务中间件Seata

1.Seata地址:https://github.com/seata/seata/issues ,下载seata-server

2.将Seata放到相应的文件目录解压,并修改conf文件夹下,修改registry.conf以及file.conf

3.修改registry.conf,以文件格式注册

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

  file {
    name = "file.conf"
  }
}

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

  file {
    name = "file.conf"
  }
}

4.修改file.conf,以文件形式时,需要通过netty通信 

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  #thread factory for netty
  threadFactory {
    bossThreadPrefix = "NettyBoss"
    workerThreadPrefix = "NettyServerNIOWorker"
    serverExecutorThreadPrefix = "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 = "8"
  }
  serialization = "seata"
  compressor = "none"
}

## transaction log store, only used in server side
store {
  ## store mode: file、db
  mode = "file"
  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
   # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://192.168.2.172:3306/seata"
    user = "root"
    password = "root"
    global.table = "global_table"
    branch.table="branch_table"
    query-limit = 100
  }
}

5.java代码,首先启动Eureka,然后,在Account服务中,写服务

package com.example.account.controller;


import com.example.account.service.ISeataAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;

/**
 * <p>
 * 账户信息表 前端控制器
 * </p>
 *
 * @author yz
 * @since 2020-04-28
 */
@RestController
@RequestMapping("/account")
public class SeataAccountController {

    @Autowired
    private ISeataAccountService accountService;

    @RequestMapping("/deduction")
    public void deduction(@RequestParam("id") Integer accountId,@RequestParam("price") BigDecimal money)  {
        accountService.deduction(accountId, money);
//        throw new RuntimeException("错误");
    }
}

  6.在Order服务中远程调用 

package com.example.orderservice.service;

import com.example.orderservice.service.impl.AccountService;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;

@FeignClient(name="account-service",fallback = AccountService.class)
public interface IAccountService {

    @RequestMapping(value = "/account/deduction",method = RequestMethod.GET)
    void deduction(@RequestParam("id") Integer accountId,@RequestParam("price") BigDecimal money);
}

  

package com.example.orderservice.controller;


import com.example.orderservice.entity.SeataOrder;
import com.example.orderservice.service.IAccountService;
import com.example.orderservice.service.ISeataOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.Random;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author yz
 * @since 2020-04-28
 */
@RestController
@RequestMapping("/order")
public class SeataOrderController {

    @Autowired
    IAccountService accountService;

    @Autowired
    ISeataOrderService orderService;

    @RequestMapping("/submit")
    @GlobalTransactional
    public void submitOrder(@RequestParam("id") Integer accountId,@RequestParam("price") BigDecimal orderPrice) {
        accountService.deduction(accountId, orderPrice);
        SeataOrder order = new SeataOrder();
        order.setOAccountId(accountId);
        order.setOGoodId(RandomUtils.nextInt());
        order.setOPrice(orderPrice.intValue());
        orderService.save(order);
//        throw new RuntimeException("错误");
        System.out.println("成功");
    }
}

  7.需要在Order和Account服务端中的resources中添加file.conf

  service {
    vgroupMapping.minbox-seata = "seata-server"
    seata-server.grouplist = "192.168.2.172:8091"
    enableDegrade = false
    disable = false
  }

  client {
    async.commit.buffer.limit = 10000
    lock {
      retry.internal = 10
      retry.times = 30
    }
}

  以上操作就可以实现分布式事务

另外 ,也可以将seata-server注入到eureka中,来使用

registry.conf

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


   eureka {
     serviceUrl = "http://192.168.2.242:8090/eureka/"
     application = "seata-server"
     weight = "1"
  }
}

 file.conf

store {
  ## store mode: file、db
  mode = "file"
  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
   # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }

}

  就可以实现分布式事务了

 启动Seata-server:./seata-server.sh