九、Seata的AT模式

9.1 什么是弱一致性 ?

弱⼀致性舍弃了强⼀致性,表示允许在某个时间点 甚⾄某个时间段 主从节点的数据不⼀致性的情况。但是这种不⼀致性只是暂时的,但是数据最终会变的⼀致性。

9.2 Seata的弱一致性

seata的四种模式 除了XA模式是强⼀致性之外 其他的三种⽐如 Saga TCC AT 都属于弱⼀致性,但是除了这些弱⼀致性的解决⽅案之外,还有可以利⽤可靠消息队列实现最终⼀致性的效果等等

AT 是Seata强烈建议使用的方式,95%的人使用Seata都会使用AT模式

9.3 Seata的AT模式介绍

AT模式和XA模式差不多,是由XA模式演化⽽来的,是Seata推荐的⼀种分布式解决⽅案,AT模式最早来源于阿⾥中间件团队发布的TXC服务。 AT模式不再像XA那样,AT模式下数据库不需要⽀持XA协议。并且AT模式和XA模式从编码模型上⼏乎⼀样,可以这样说,会XA的编码 就会AT的编码。

9.4 AT模式流程图

在这里插入图片描述

9.5 AT模式注意点

9.6 全局锁的理解

1、认识全局锁

全局锁由表名和操作记录的主键 按照⼀定的规律组成。 seata的AT模式 全局锁保存在TC端(seata-server端) TC端保存全局锁可以在如下三个位置 redis mysql file(默认)

2、注册全局锁

RM 向TC注册分⽀事务,在注册分⽀事务之后,将会操作数据库修改数据,提交事务 之前,将会把修改的表和主键信息封装成全局锁,发送到TC服务器进⾏注册,如果TC服务器发现已经有这个主键 的全局锁 证明有其他事务正在执⾏这条数据 则会跑出全局锁冲突异常,客户端会循环等待并且重试

3、校验(获取)全局锁

提交本地事务时 先要获取这个全局锁,当能获取到全局锁 则会提交本地事务 如果全局锁被占⽤则表示有其他事务在操作这条数据。客户端等待 重试获取锁

4、释放锁

第⼆阶段是异步执⾏的,在TC向RM(客户端)发送 branch Commit请求后,客户端仅将分⽀提交信息插⼊内存列队中,可以理解为 如果第⼀阶段成功,第⼆阶段不出异常的情况下,第⼆阶段⼀开始就会释放全局锁,不会锁定到第⼆阶段执⾏结束才会释放全局锁

5、结论

全局锁将会被客户端持有到第⼆阶段的开始 所以性能不如本地事务⾼


9.7 AT的多数据源场景

9.8 AT的分库分表场景

1、环境搭建

见 gitee at_sharding_demo 模块下

2、shardingsphere 整合 Seata

  1. 所有的库中添加 undo表
-- 数据库aaa和bbb都要添加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,
 PRIMARY KEY (`id`),
 UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  1. 添加依赖
<!-- seata -->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.5.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/
       sharding-transaction-base-seata-at -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-transaction-base-seata-at</artifactId>
            <version>4.1.1</version>
        </dependency>

2)在资源路径下创建seata.conf
在这里插入图片描述

## 默认值可以不配置
sharding.transaction.seata.at.enable=true
## 配置值和 application-id ⼀致
client.application.id=xyz
## 配置值和 tx-service-group的值保持⼀致
client.transaction.service.group=shangma

3)yaml中编写 seata配置

seata:
  application-id: xyz
  service:
    vgroup-mapping:
      shangma: default
    grouplist:
      default: 127.0.0.1:8091
  tx-service-group: shangma
  1. 添加注解@Transactional + @ShardingTransactionType(TransactionType.BASE)
  @GetMapping("/transfer")
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public String transfer(Long fromId, Long toId, double money) {
        User fromUser = userMapper.findById(fromId);
        User toUser = userMapper.findById(toId);
        fromUser.setMoney(fromUser.getMoney() - money);
        toUser.setMoney(toUser.getMoney() + money);
        userMapper.updateUser(fromUser);
        int i = 1 / 0;
        userMapper.updateUser(toUser);
        return "success";
    }

请求: http://localhost:8080/transfer?fromId=1&toId=2&money=100
在这里插入图片描述

9.9 AT的微服务场景

1、微服务环境搭建

见 jitee : at-cloud-master

2、AT模式解决微服务分布式事务

1) 添加 undo 表
三个库都要添加undo表

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,
 PRIMARY KEY (`id`),
 UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2)common 添加依赖

 <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.seata/seata-spring-boot
       -starter -->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <optional>true</optional>
        </dependency>

3)四个服务都要添加seata配置

seata:
  service:
    vgroup-mapping:
      huige: default
    grouplist:
      default: 127.0.0.1:8091
  tx-service-group: huige

4)common工程添加 druid数据源配置
(上面说过使用默认的hakari数据源,分布式事务不生效)

@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
public class DbConfig {


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

5)business系统排除 TCC

@SpringBootApplication(exclude = SeataTCCFenceAutoConfiguration.class)
@EnableFeignClients
public class ATBusinessApp {
    public static void main(String[] args) {
        SpringApplication.run(ATBusinessApp.class, args);
    }
}

6) 业务系统添加 Global 注解

@GlobalTransactional
    public void placeOrder(int accountId, int goodId, int num) {
        Good good = goodFeignClient.findById(goodId);
        double amount = good.getGoodPrice() * num;
        Order order = new Order().setGoodId(goodId).setGoodNum(num).setAccountId(accountId).setOrderAmount(amount).setStatus(OrderStatus.CREATE.getValue());
        // 创建订单
        orderFeignClient.addOrder(order);
        // 减库存
        goodFeignClient.reduceStock(goodId, num);
        // 减余额
        accountFeignClient.reduceMoney(accountId, amount);
    }

9.10 AT微服务加分库场景(必须会)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值