java 分布式事务的实现方式之TCC方案

TCC 是一种补偿性的事务模式,它通过在事务执行之前定义 Try、Confirm 和 Cancel 三个阶段来实现事务的一致性。

  • Try 阶段:

在 Try 阶段,业务逻辑会尝试预留所需的资源和执行必要的检查,但不会真正进行数据修改。它会预留相关资源,并执行一些预检查,以确保后续的 Confirm 阶段可以成功执行。
如果 Try 阶段执行成功,则事务可以进入 Confirm 阶段。如果 Try 阶段失败,则事务进入 Cancel 阶段。

  • Confirm 阶段:

在 Confirm 阶段,业务逻辑会真正执行事务操作,对数据进行修改,释放预留的资源,并确认事务的最终结果。
Confirm 阶段应该是幂等的,即多次执行 Confirm 操作的结果应该是一致的。

  • Cancel 阶段:

在 Cancel 阶段,业务逻辑会回滚 Try 阶段所预留的资源和对数据的修改,将系统恢复到事务执行前的状态。
Cancel 阶段也应该是幂等的,即多次执行 Cancel 操作的结果应该是一致的。
TCC 方案相比于三阶段提交具有更细粒度的控制和灵活性,它允许应用根据实际业务需求来定义 Try、Confirm 和 Cancel 阶段的逻辑,并提供了补偿机制来处理异常情况。TCC 方案相对来说更加适用于复杂的业务场景,但也需要应用开发者自行实现和管理补偿逻辑。而三阶段提交是一个标准的分布式事务协议,需要基于该协议来实现协调者和参与者的逻辑,以保证事务的一致性。

以下是使用 Spring Boot 框架实现 TCC 方案的示例代码:

首先,添加所需的依赖项到 pom.xml 文件中:

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- Spring Boot Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- H2 Database -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>

接下来,创建一个数据库实体类 Order,表示订单信息:

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;

@Entity
@Table(name = "orders")
public class Order {
    @Id
    private String id;
    private BigDecimal amount;
    private String status;

    // 构造函数、Getter 和 Setter 省略...
}

然后,创建一个订单的数据库访问接口 OrderRepository,使用 Spring Data JPA:

import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, String> {
}

接下来,创建一个 TCC 服务接口 PaymentService,定义 Try、Confirm 和 Cancel 阶段的方法:

public interface PaymentService {
    boolean tryPayment(String orderId, BigDecimal amount);
    boolean confirmPayment(String orderId);
    boolean cancelPayment(String orderId);
}

然后,实现 PaymentService 接口的具体逻辑,创建一个名为 PaymentServiceImpl 的类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PaymentServiceImpl implements PaymentService {
    @Autowired
    private OrderRepository orderRepository;

    @Override
    public boolean tryPayment(String orderId, BigDecimal amount) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order != null && "PENDING".equals(order.getStatus())) {
            // 执行 Try 阶段的逻辑,预留资源和执行预检查
            // 返回 true 表示 Try 阶段成功
            return true;
        }
        return false; // Try 阶段失败
    }

    @Override
    @Transactional
    public boolean confirmPayment(String orderId) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order != null && "PENDING".equals(order.getStatus())) {
            // 执行 Confirm 阶段的逻辑,实际支付操作和修改订单状态
            order.setStatus("PAID");
            orderRepository.save(order);
            return true; // Confirm 阶段成功
        }
        return false; // Confirm 阶段失败
    }

    @Override
    @Transactional
    public boolean cancelPayment(String orderId) {
        Order order = orderRepository.findById(orderId).orElse(null);
        if (order != null && "PENDING".equals(order.getStatus())) {
            // 执行 Cancel 阶段的逻辑,回滚 Try 阶段的操作,不修改订单状态
            return true; // Cancel 阶段成功
        }
        return false; // Cancel 阶段失败
    }
}

最后,创建一个示例的业务逻辑类 OrderService,在其中使用 TCC 方案处理订单的下单流程:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService;

    @Transactional
    public void placeOrder(String orderId, BigDecimal amount) {
        boolean tryResult = paymentService.tryPayment(orderId, amount);
        if (tryResult) {
            try {
                // 执行业务逻辑,创建订单等操作

                boolean confirmResult = paymentService.confirmPayment(orderId);
                if (confirmResult) {
                    // 提交事务
                } else {
                    // 事务回滚,执行 Cancel 阶段的逻辑
                    paymentService.cancelPayment(orderId);
                    throw new RuntimeException("Confirm payment failed");
                }
            } catch (Exception e) {
                // 异常处理,执行 Cancel 阶段的逻辑
                paymentService.cancelPayment(orderId);
                throw e;
            }
        } else {
            throw new RuntimeException("Try payment failed");
        }
    }
}

这是一个简单的示例,演示了如何使用 Java 和 Spring Boot 实现 TCC 方案。在实际应用中,你可能需要根据具体业务需求进行适当的调整和扩展,例如添加日志记录、错误处理等。
如果是在真实的分布式环境中,建议采用kafka来进行分布式消息的传递。

猜你喜欢

转载自blog.csdn.net/yuanchengfu0910/article/details/131208959