由于目前互联网企业的兴起,越来越多的企业开始采用微服务架构模式。微服务架构模式的确提升后台服务的性能,保证服务的高可用等优点,但是同时也带来了一个问题,即如何保证数据的一致性、操作原子性,即分布式事务。目前,互联网主要有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