分布式seata案例学习-2

上篇文章学习了如何安装seata,先学习如何使用
事务的4个特性ACID
事务特性
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
at模式详解
AT模式运行机制
AT模式的特点就是对业务无入侵式,整体机制分二阶段提交
两阶段提交协议的演变:

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
  • 二阶段:
    • 提交异步化,非常快速地完成。
    • 回滚通过一阶段的回滚日志进行反向补偿。
      在 AT 模式下,用户只需关注自己的业务SQL,用户的业务SQL 作为一阶段,Seata 框架会自动生成事务的二阶段提交和回滚操作。
      在这里插入图片描述

Seata具体实现步骤

  1. TM端使用@GlobalTransaction进行全局事务开启、提交、回滚
  2. TM开始RPC调用远程服务
  3. RM端seata-client通过扩展DataSourceProxy,实现自动生成UNDO_LOG与TC上报
  4. TM告知TC提交/回滚全局事务
  5. TC通知RM各自执行commit/rollback操作,同时清除undo_log

RM实现

  1. 创建订单和库存服务的DB
-- 库存服务DB执行
CREATE TABLE `tab_storage` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `product_id` bigint(11) DEFAULT NULL COMMENT '产品id',
  `total` int(11) DEFAULT NULL COMMENT '总库存',
  `used` int(11) DEFAULT NULL COMMENT '已用库存',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO `tab_storage` (`product_id`, `total`,`used`)VALUES ('1', '96', '4');
INSERT INTO `tab_storage` (`product_id`, `total`,`used`)VALUES ('2', '100','0');

-- 订单服务DB执行
CREATE TABLE `tab_order` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(11) DEFAULT NULL COMMENT '用户id',
  `product_id` bigint(11) DEFAULT NULL COMMENT '产品id',
  `count` int(11) DEFAULT NULL COMMENT '数量',
  `money` decimal(11,0) DEFAULT NULL COMMENT '金额',
  `status` int(1) DEFAULT NULL COMMENT '订单状态:0:创建中;1:已完成',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

  1. 各数据库加入undo_log表
CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

  1. 编写业务代码

库存代码

package com.seata.storage;

import com.seata.storage.model.Storage;
import com.seata.storage.service.StorageService;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@SpringBootApplication
@MapperScan("com.seata.storage.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class StorageApplication {
    @Autowired
    private StorageService storageService;

    @GetMapping("storage/change")
    public Boolean change(long used , long productId){
        Storage storage = new Storage();
        storage.setTotal(100)
                .setProductId(productId)
                .setUsed(3);
        return storageService.create(storage);
    }
    public static void main(String[] args) {
        SpringApplication.run(StorageApplication.class, args);
    }
}

订单代码

package com.seata.order;

import com.seata.order.model.Order;
import com.seata.order.service.OrderService;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;

@RestController
@SpringBootApplication
@MapperScan("com.seata.order.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {
    @Autowired
    private OrderService orderService;

    @GetMapping("order/create")
    public Boolean create(long userId , long productId){
        Order order = new Order();
        order.setCount(1)
                .setMoney(BigDecimal.valueOf(88))
                .setProductId(productId)
                .setUserId(userId)
                .setStatus(0);
        return orderService.create(order);
    }
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

}

  1. 测试业务代码是否正常运行(完整代码见附件链接:https://pan.baidu.com/s/1vnaulywP-GLk5rGvtJulPg?pwd=e7vk
    提取码:e7vk)
  2. 在这里插入图片描述
  3. TM实现
    搭建business服务,pom、bootstrap.yml与RM基本一致,并提供FeignClient调用组件
    FeignClient组件代码编写
@FeignClient(value = "storage-service")
@Component
public interface StorageClient {
    @GetMapping("api/storage/change")
    Boolean changeStorage(@RequestParam("productId") long productId , @RequestParam("used")  int used);
}

@FeignClient(value = "order-service")
@Component
public interface OrderClient {
    @GetMapping("api/order/create")
    Boolean create(@RequestParam("userId") long userId , @RequestParam("productId") long productId);
}

调用层代码编写

package com.seata.business;

import com.seata.business.feign.OrderClient;
import com.seata.business.feign.StorageClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
@EnableFeignClients
@EnableDiscoveryClient
public class BusinessApplication {
    @Autowired
    private OrderClient orderClient;
    @Autowired
    private StorageClient storageClient;
    @GetMapping("buy")
    @GlobalTransactional
    public String buy(long userId , long productId){
        orderClient.create(userId , productId);
        storageClient.changeStorage(userId , 1);
        return "ok";
    }
    public static void main(String[] args) {
        SpringApplication.run(BusinessApplication.class, args);
    }

}

TM测试请求
在这里插入图片描述
如果在order与storage服务器出现以下语句表示分布式事务成功
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值