18.9.7 分布式事务解决方案(2PC/TCC/Saga)

1. 分布式事务基础概念

1.1 分布式事务问题

public class DistributedTransactionPrinciple {
    
    /*
     * 分布式事务核心问题:
     * 
     * 1. ACID特性挑战
     *    - 原子性:多个服务要么全成功要么全失败
     *    - 一致性:数据状态保持一致
     *    - 隔离性:并发事务互不影响
     *    - 持久性:提交后数据持久保存
     * 
     * 2. 常见场景
     *    - 订单支付:订单服务 + 支付服务 + 库存服务
     *    - 转账业务:账户A扣款 + 账户B加款
     *    - 电商下单:创建订单 + 扣减库存 + 扣减积分
     * 
     * 3. 解决方案
     *    - 2PC (Two-Phase Commit)
     *    - TCC (Try-Confirm-Cancel)
     *    - Saga 模式
     *    - 本地消息表
     *    - 最大努力通知
     */
    
    public void demonstrateDistributedTransaction() {
        System.out.println("=== 分布式事务问题演示 ===");
        
        demonstrateOrderPaymentScenario();
        demonstrateTransferScenario();
    }
    
    private void demonstrateOrderPaymentScenario() {
        System.out.println("--- 订单支付场景 ---");
        
        OrderService orderService = new OrderService();
        PaymentService paymentService = new PaymentService();
        InventoryService inventoryService = new InventoryService();
        
        System.out.println("1. 用户下单购买商品:");
        String orderId = "order-001";
        String userId = "user-123";
        String productId = "product-456";
        int quantity = 2;
        double amount = 199.99;
        
        System.out.println("  订单ID: " + orderId);
        System.out.println("  商品: " + productId + " x " + quantity);
        System.out.println("  金额: " + amount);
        
        System.out.println("\n2. 需要保证事务一致性:");
        System.out.println("  - 创建订单成功");
        System.out.println("  - 扣减库存成功");
        System.out.println("  - 支付扣款成功");
        System.out.println("  - 任一步骤失败则全部回滚");
        
        System.out.println("\n3. 分布式事务挑战:");
        System.out.println("  - 网络分区可能导致部分成功");
        System.out.println("  - 服务故障可能导致状态不一致");
        System.out.println("  - 需要协调多个服务的事务状态");
        System.out.println();
    }
    
    private void demonstrateTransferScenario() {
        System.out.println("--- 转账业务场景 ---");
        
        System.out.println("1. 用户A向用户B转账:");
        System.out.println("  转出账户: account-A");
        System.out.println("  转入账户: account-B");
        System.out.println("  转账金额: 1000元");
        
        System.out.println("\n2. 事务要求:");
        System.out.println("  - 账户A扣款1000元");
        System.out.println("  - 账户B加款1000元");
        System.out.println("  - 保证资金总额不变");
        
        System.out.println("\n3. 可能的问题:");
        System.out.println("  - A扣款成功,B加款失败");
        System.out.println("  - 网络故障导致状态未知");
        System.out.println("  - 需要保证最终一致性");
        System.out.println();
    }
}

// 订单服务
class OrderService {
    public boolean createOrder(String orderId, String userId, String productId, int quantity) {
        System.out.println("  订单服务: 创建订单 " + orderId);
        // 模拟订单创建逻辑
        return true;
    }
    
    public void cancelOrder(String orderId) {
        System.out.println("  订单服务: 取消订单 " + orderId);
    }
}

// 支付服务
class PaymentService {
    public boolean deductAmount(String userId, double amount) {
        System.out.println("  支付服务: 扣款 " + amount + " 元");
        // 模拟支付扣款逻辑
        return true;
    }
    
    public void refund(String userId, double amount) {
        System.out.println("  支付服务: 退款 " + amount + " 元");
    }
}

// 库存服务
class InventoryService {
    public boolean deductInventory(String productId, int quantity) {
        System.out.println("  库存服务: 扣减库存 " + quantity + " 个");
        // 模拟库存扣减逻辑
        return true;
    }
    
    public void restoreInventory(String productId, int quantity) {
        System.out.println("  库存服务: 恢复库存 " + quantity + " 个");
    }
}

2. 2PC两阶段提交

2.1 2PC实现原理

public class TwoPhaseCommitDemo {
    
    /*
     * 2PC两阶段提交:
     * 
     * 阶段一:准备阶段 (Prepare Phase)
     * - 协调者向所有参与者发送准备请求
     * - 参与者执行事务但不提交,返回准备结果
     * 
     * 阶段二:提交阶段 (Commit Phase)
     * - 如果所有参与者都准备成功,协调者发送提交请求
     * - 如果任一参与者准备失败,协调者发送回滚请求
     * 
     * 优点:强一致性保证
     * 缺点:阻塞式协议,性能较差,存在单点故障
     */
    
    public void demonstrate2PC() {
        System.out.println("=== 2PC两阶段提交演示 ===");
        
        TwoPhaseCommitCoordinator coordinator = new TwoPhaseCommitCoordinator();
        
        // 添加参与者
        coordinator.addParticipant(new OrderServiceParticipant("order-service"));
        coordinator.addParticipant(new PaymentServiceParticipant("payment-service"));
        coordinator.addParticipant(new InventoryServiceParticipant("inventory-service"));
        
        demonstrate2PCSuccess(coordinator);
        demonstrate2PCFailure(coordinator);
    }
    
    private void demonstrate2PCSuccess(TwoPhaseCommitCoordinator coordinator) {
        System.out.println("--- 2PC成功场景 ---");
        
        TransactionContext context = new TransactionContext("tx-001");
        context.addOperation("createOrder", "order-001");
        context.addOperation("deductPayment", "1000.0");
        context.addOperation("deductInventory", "product-001:2");
        
        boolean result = coordinator.executeTransaction(context);
        System.out.println("事务执行结果: " + (result ? "成功" : "失败"));
        System.out.println();
    }
    
    private void demonstrate2PCFailure(TwoPhaseCommitCoordinator coordinator) {
        System.out.println("--- 2PC失败场景 ---");
        
        TransactionContext context = new TransactionContext("tx-002");
        context.addOperation("createOrder", "order-002");
        context.addOperation("deductPayment", "insufficient"); // 模拟支付失败
        context.addOperation("deductInventory", "product-002:1");
        
        boolean result = coordinator.executeTransaction(context);
        System.out.println("事务执行结果: " + (result ? "成功" : "失败"));
        System.out.println();
    }
}

// 事务上下文
class TransactionContext {
    private String transactionId;
    private java.util.Map<String, String> operations = new java.util.HashMap<>();
    
    public TransactionContext(String transactionId) {
        this.transactionId = transactionId;
    }
    
    public void addOperation(String operation, String data) {
        operations.put(operation, data);
    }
    
    public String getTransactionId() { return transactionId; }
    public java.util.Map<String, String> getOperations() { return operations; }
}

// 2PC协调者
class TwoPhaseCommitCoordinator {
    private java.util.List<TransactionParticipant> participants = new java.util.ArrayList<>();
    
    public void addParticipant(TransactionParticipant participant) {
        participants.add(participant);
    }
    
    public boolean executeTransaction(TransactionContext context) {
        System.out.println("开始执行2PC事务: " + context.getTransactionId());
        
        // 阶段一:准备阶段
        System.out.println("\n=== 阶段一:准备阶段 ===");
        boolean allPrepared = true;
        
        for (TransactionParticipant participant : participants) {
            boolean prepared = participant.prepare(context);
            System.out.println(participant.getName() + " 准备结果: " + (prepared ? "成功" : "失败"));
            
            if (!prepared) {
                allPrepared = false;
                break;
            }
        }
        
        // 阶段二:提交或回滚阶段
        System.out.println("\n=== 阶段二:" + (allPrepared ? "提交" : "回滚") + "阶段 ===");
        
        if (allPrepared) {
            // 所有参与者准备成功,执行提交
            for (TransactionP

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论

相关推荐

Aurora23:属于挂一半,暂时进池子了,隔一段时间没有其他组捞的话就彻底结束了
点赞 评论 收藏
分享
牛客吹哨人:哨哥晚点统一更新到黑名单:能救一个是一个!26届毁意向毁约裁员黑名单https://www.nowcoder.com/discuss/1525833
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务