黑马商城 Spring Cloud 微服务课程笔记:分布式事务 - Seata 的架构和原理

目录

黑马商城 Spring Cloud 微服务课程笔记:分布式事务 - Seata 的架构和原理

一、Seata 解决的问题场景

二、Seata 的架构

三、Seata 的原理


在黑马商城的微服务架构中,当涉及到多个微服务协同完成一个业务操作时,分布式事务的处理变得至关重要。其中,Seata 是一个开源的分布式事务解决方案,用于解决微服务架构中的分布式事务问题。

一、Seata 解决的问题场景

在黑马商城中,例如用户下单购买商品这个业务场景,涉及到订单服务创建订单、库存服务扣减库存、用户服务扣除积分等多个微服务操作。如果这些操作不能保证在一个事务内执行,就可能出现部分操作成功、部分操作失败的情况,导致数据不一致。Seata 就是为了解决这种分布式事务场景下的数据一致性问题。

二、Seata 的架构

  1. TC(Transaction Coordinator)- 事务协调者
    • 负责协调和管理全局事务,是全局事务的核心管理者。它接收事务发起者的请求,协调各个参与者的事务执行,决定事务是提交还是回滚。
    • 代码示例(伪代码,实际 Seata TC 是独立部署的服务,这里只是示意其协调逻辑):

public class TransactionCoordinator {
    private List participants;

    public TransactionCoordinator(List participants) {
        this.participants = participants;
    }

    public void handleTransaction() {
        // 向参与者发送准备请求
        for (TransactionParticipant participant : participants) {
            participant.prepare();
        }
        // 收集参与者的准备结果
        boolean allPrepared = true;
        for (TransactionParticipant participant : participants) {
            if (!participant.isPrepared()) {
                allPrepared = false;
                break;
            }
        }
        if (allPrepared) {
            // 所有参与者准备成功,发送提交请求
            for (TransactionParticipant participant : participants) {
                participant.commit();
            }
        } else {
            // 有参与者准备失败,发送回滚请求
            for (TransactionParticipant participant : participants) {
                participant.rollback();
            }
        }
    }
}

  1. TM(Transaction Manager)- 事务管理器
    • 定义全局事务的范围,开始全局事务、提交或回滚全局事务。它与业务逻辑紧密结合,负责将业务操作纳入到分布式事务管理中。
    • 代码示例(伪代码,假设在订单服务中使用):

import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;

@Service
public class OrderService {
    @GlobalTransactional
    public void createOrder() {
        // 业务逻辑,创建订单,调用其他服务等
        // 这里的方法执行就会被Seata的TM纳入到全局事务管理中
    }
}

  1. RM(Resource Manager)- 资源管理器
    • 管理分支事务的资源,如数据库连接等。它负责向 TC 注册分支事务,报告分支事务的状态,并根据 TC 的指令执行本地事务的提交或回滚。
    • 以数据库为例,假设在库存服务中使用 Seata 管理数据库事务(伪代码):

import javax.sql.DataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SeataDataSourceConfig {
    @Bean
    public DataSource dataSource() {
        // 假设这里获取到了实际的数据源,比如DruidDataSource等
        DataSource actualDataSource = // 获取实际数据源的代码
        return new DataSourceProxy(actualDataSource);
    }
}

三、Seata 的原理

  1. 一阶段(执行本地事务并注册分支事务)
    • 当业务操作开始时,TM 向 TC 发起全局事务开始请求,TC 生成全局事务 ID 并返回给 TM。
    • 各个微服务(RM)执行本地事务,在执行本地事务前,RM 会向 TC 注册分支事务,将自己纳入到全局事务管理中。
    • 本地事务执行完成后,RM 会向 TC 报告本地事务的执行状态(成功或失败)。
    • 代码示例(结合前面的订单、库存服务示例,假设库存服务执行本地事务并注册分支事务):

import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.TransactionalExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class StockService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GlobalTransactional
    public void deductStock() {
        // 获取全局事务ID
        String xid = RootContext.getXID();
        try {
            // 执行本地事务,扣减库存
            jdbcTemplate.update("UPDATE stock SET quantity = quantity - 1 WHERE product_id =?", 1);
            // 向TC注册分支事务,这里假设已经有相关的Seata客户端配置
            TransactionalExecutor.registerBranchTransaction(xid, "库存服务", null);
        } catch (Exception e) {
            // 如果本地事务执行失败,向TC报告失败状态,这里简化处理,实际可能需要更完善的错误处理
            TransactionalExecutor.reportFailure(xid, e);
            throw e;
        }
    }
}

  1. 二阶段(提交或回滚全局事务)
    • 提交阶段
      • 如果所有分支事务的一阶段都执行成功并且向 TC 报告了成功状态,TC 会向所有 RM 发送提交请求。
      • RM 收到提交请求后,提交本地事务。
    • 回滚阶段
      • 如果有任何一个分支事务在一阶段执行失败或者向 TC 报告了失败状态,TC 会向所有 RM 发送回滚请求。
      • RM 收到回滚请求后,根据一阶段记录的 undo 日志进行回滚操作,将数据恢复到事务开始前的状态。
    • 代码示例(Seata 的二阶段提交和回滚操作是由 Seata 框架自动处理的,这里无法给出详细的代码实现,但可以简单示意回滚逻辑的思路,假设在库存服务中处理回滚):

import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import io.seata.tm.api.TransactionalExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class StockService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GlobalTransactional
    public void deductStock() {
        String xid = RootContext.getXID();
        try {
            // 执行本地事务,扣减库存
            jdbcTemplate.update("UPDATE stock SET quantity = quantity - 1 WHERE product_id =?", 1);
            // 向TC注册分支事务等操作(前面已示例)
        } catch (Exception e) {
            // 如果本地事务执行失败,向TC报告失败状态(前面已示例)
            // 假设这里收到TC的回滚请求后,进行回滚操作
            if (TransactionalExecutor.isRollbackOnly(xid)) {
                // 根据undo日志进行回滚,这里简化为直接增加库存(实际需要根据undo日志正确恢复数据)
                jdbcTemplate.update("UPDATE stock SET quantity = quantity + 1 WHERE product_id =?", 1);
            }
            throw e;
        }
    }
}

Seata 通过其独特的架构和事务处理原理,为黑马商城的微服务架构提供了有效的分布式事务解决方案,确保在复杂的微服务协作场景下数据的一致性。在实际应用中,需要根据具体的业务需求和技术架构合理配置和使用 Seata。

你可能感兴趣的:(java,架构,spring,cloud,微服务)