Java学习第16天 - 分布式事务与数据一致性

学习时间: 4-5小时
学习目标: 掌握分布式事务管理,学会使用Seata实现分布式事务,理解数据一致性保证


详细学习清单


✅ 第一部分:分布式事务基础概念(60分钟)

1. 分布式事务的挑战

分布式事务问题分析

java 复制代码
// DistributedTransactionChallenges.java
package com.example.demo.distributed;

import java.util.List;
import java.util.ArrayList;

public class DistributedTransactionChallenges {
    
    public static class Challenge {
        private String name;
        private String description;
        private String example;
        private String solution;
        
        public Challenge(String name, String description, String example, String solution) {
            this.name = name;
            this.description = description;
            this.example = example;
            this.service = solution;
        }
        
        // Getter方法
        public String getName() { return name; }
        public String getDescription() { return description; }
        public String getExample() { return example; }
        public String getSolution() { return solution; }
    }
    
    public static void main(String[] args) {
        List<Challenge> challenges = new ArrayList<>();
        
        // 网络分区问题
        challenges.add(new Challenge(
            "网络分区",
            "分布式系统中网络不稳定导致节点间通信中断",
            "订单服务无法连接库存服务,导致数据不一致",
            "使用心跳检测、超时重试、熔断器模式"
        ));
        
        // 时钟同步问题
        challenges.add(new Challenge(
            "时钟同步",
            "不同节点时钟不同步,影响事务顺序判断",
            "两个订单同时创建,时间戳相同但顺序错误",
            "使用逻辑时钟、向量时钟、全局序列号"
        ));
        
        // 数据一致性问题
        challenges.add(new Challenge(
            "数据一致性",
            "多个服务数据状态不一致,违反业务规则",
            "订单已创建但库存未扣减,或支付成功但订单未更新",
            "使用分布式事务、最终一致性、补偿机制"
        ));
        
        // 服务可用性问题
        challenges.add(new Challenge(
            "服务可用性",
            "某个服务不可用影响整个业务流程",
            "支付服务宕机导致订单无法完成",
            "使用服务降级、异步处理、消息队列"
        ));
        
        System.out.println("=== 分布式事务主要挑战 ===");
        for (Challenge challenge : challenges) {
            System.out.println("\n挑战名称: " + challenge.getName());
            System.out.println("问题描述: " + challenge.getDescription());
            System.out.println("具体示例: " + challenge.getExample());
            System.out.println("解决方案: " + challenge.getSolution());
        }
    }
}

2. CAP理论与BASE理论

CAP理论分析

java 复制代码
// CAPTheory.java
package com.example.demo.distributed;

import java.util.HashMap;
import java.util.Map;

public class CAPTheory {
    
    public static class CAPProperty {
        private String name;
        private String description;
        private String tradeoff;
        private List<String> examples;
        
        public CAPProperty(String name, String description, String tradeoff) {
            this.name = name;
            this.description = description;
            this.tradeoff = tradeoff;
            this.examples = new ArrayList<>();
        }
        
        public void addExample(String example) {
            this.examples.add(example);
        }
        
        // Getter方法
        public String getName() { return name; }
        public String getDescription() { return description; }
        public String getTradeoff() { return tradeoff; }
        public List<String> getExamples() { return examples; }
    }
    
    public static void main(String[] args) {
        Map<String, CAPProperty> capProperties = new HashMap<>();
        
        // 一致性 (Consistency)
        CAPProperty consistency = new CAPProperty(
            "一致性 (Consistency)",
            "所有节点在同一时间看到的数据是一致的",
            "强一致性 vs 可用性"
        );
        consistency.addExample("银行转账:A账户扣款,B账户必须同时增加");
        consistency.addExample("库存管理:所有节点看到的库存数量必须一致");
        capProperties.put("C", consistency);
        
        // 可用性 (Availability)
        CAPProperty availability = new CAPProperty(
            "可用性 (Availability)",
            "每个请求都能收到响应,但不保证是最新数据",
            "服务可用 vs 数据一致性"
        );
        availability.addExample("电商网站:即使数据不是最新的,也要能正常访问");
        availability.addExample("缓存系统:优先返回缓存数据,保证响应速度");
        capProperties.put("A", availability);
        
        // 分区容错性 (Partition Tolerance)
        CAPProperty partitionTolerance = new CAPProperty(
            "分区容错性 (Partition Tolerance)",
            "系统在网络分区情况下仍能继续工作",
            "网络分区 vs 系统可用性"
        );
        partitionTolerance.addExample("微服务架构:服务间网络中断时仍能独立工作");
        partitionTolerance.addExample("分布式存储:部分节点不可用时仍能提供服务");
        capProperties.put("P", partitionTolerance);
        
        System.out.println("=== CAP理论分析 ===");
        for (Map.Entry<String, CAPProperty> entry : capProperties.entrySet()) {
            CAPProperty property = entry.getValue();
            System.out.println("\n" + entry.getKey() + " - " + property.getName());
            System.out.println("描述: " + property.getDescription());
            System.out.println("权衡: " + property.getTradeoff());
            System.out.println("示例:");
            for (String example : property.getExamples()) {
                System.out.println("  - " + example);
            }
        }
        
        System.out.println("\n=== CAP理论组合 ===");
        System.out.println("CP (一致性+分区容错): 如分布式数据库");
        System.out.println("AP (可用性+分区容错): 如NoSQL数据库");
        System.out.println("CA (一致性+可用性): 单机系统,无法实现分区容错");
    }
}

✅ 第二部分:Seata分布式事务框架(90分钟)

1. Seata架构与配置

Seata服务配置

xml 复制代码
<!-- seata-server/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>microservice-parent</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>seata-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-server</artifactId>
            <version>1.7.0</version>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
    </dependencies>
</project>

Seata配置文件

conf 复制代码
# seata-server/conf/registry.conf
registry {
  type = "nacos"
  
  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    username = "nacos"
    password = "nacos"
  }
}

config {
  type = "nacos"
  
  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = ""
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
}

Seata服务端配置

conf 复制代码
# seata-server/conf/file.conf
service {
  vgroupMapping.my_test_tx_group = "default"
  default.grouplist = "127.0.0.1:8091"
  enableDegrade = false
  disableGlobalTransaction = false
}

client {
  rm {
    asyncCommitBufferLimit = 10000
    lock {
      retryInterval = 10
      retryTimes = 30
      retryPolicyBranchRollbackOnConflict = true
    }
    reportRetryCount = 5
    tableMetaCheckEnable = false
    reportSuccessEnable = false
  }
  
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
  }
  
  undo {
    dataValidation = true
    logSerialization = "jackson"
    onlyCareUpdateColumns = true
    compress {
      enable = true
      type = zip
      threshold = 64k
    }
  }
}

store {
  mode = "db"
  
  db {
    url = "jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"
    dbType = "mysql"
    driverClassName = "com.mysql.cj.jdbc.Driver"
    username = "seata"
    password = "seata123"
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }
}

2. 业务服务集成Seata

订单服务配置

xml 复制代码
<!-- order-service/pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>microservice-parent</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>order-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.7.0</version>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>

订单服务配置

yaml 复制代码
# order-service/src/main/resources/application.yml
server:
  port: 8081

spring:
  application:
    name: order-service
  datasource:
    url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  cloud:
    alibaba:
      seata:
        tx-service-group: my_test_tx_group

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000

logging:
  level:
    io.seata: debug
    com.example.order: debug

# Seata配置
seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: my_test_tx_group
  enable-auto-data-source-proxy: true
  service:
    vgroup-mapping:
      my_test_tx_group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace: ""
      username: nacos
      password: nacos
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: ""
      group: SEATA_GROUP
      username: nacos
      password: nacos
      data-id: seataServer.properties

3. 订单服务实现

订单实体类

java 复制代码
// Order.java
package com.example.order.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Order {
    
    private Long id;
    private String orderNumber;
    private Long userId;
    private Long productId;
    private Integer quantity;
    private BigDecimal unitPrice;
    private BigDecimal totalAmount;
    private String status; // PENDING, PAID, CANCELLED, COMPLETED
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private String remark;

    // 构造函数
    public Order() {}

    public Order(String orderNumber, Long userId, Long productId, Integer quantity, BigDecimal unitPrice) {
        this.orderNumber = orderNumber;
        this.userId = userId;
        this.productId = productId;
        this.quantity = quantity;
        this.unitPrice = unitPrice;
        this.totalAmount = unitPrice.multiply(new BigDecimal(quantity));
        this.status = "PENDING";
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
    }

    // Getter和Setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getOrderNumber() { return orderNumber; }
    public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; }

    public Long getUserId() { return userId; }
    public void setUserId(Long userId) { this.userId = userId; }

    public Long getProductId() { return productId; }
    public void setProductId(Long productId) { this.productId = productId; }

    public Integer getQuantity() { return quantity; }
    public void setQuantity(Integer quantity) { this.quantity = quantity; }

    public BigDecimal getUnitPrice() { return unitPrice; }
    public void setUnitPrice(BigDecimal unitPrice) { this.unitPrice = unitPrice; }

    public BigDecimal getTotalAmount() { return totalAmount; }
    public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; }

    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }

    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }

    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }

    public String getRemark() { return remark; }
    public void setRemark(String remark) { this.remark = remark; }
}

订单服务接口

java 复制代码
// OrderService.java
package com.example.order.service;

import com.example.order.model.Order;
import java.util.List;

public interface OrderService {
    
    /**
     * 创建订单
     */
    Order createOrder(Order order);
    
    /**
     * 根据ID获取订单
     */
    Order getOrderById(Long id);
    
    /**
     * 根据用户ID获取订单列表
     */
    List<Order> getOrdersByUserId(Long userId);
    
    /**
     * 更新订单状态
     */
    boolean updateOrderStatus(Long orderId, String status);
    
    /**
     * 删除订单
     */
    boolean deleteOrder(Long id);
    
    /**
     * 获取所有订单
     */
    List<Order> getAllOrders();
}

订单服务实现

java 复制代码
// OrderServiceImpl.java
package com.example.order.service.impl;

import com.example.order.model.Order;
import com.example.order.mapper.OrderMapper;
import com.example.order.service.OrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Override
    @Transactional
    public Order createOrder(Order order) {
        // 生成订单号
        if (order.getOrderNumber() == null) {
            order.setOrderNumber(generateOrderNumber());
        }
        
        // 计算总金额
        if (order.getTotalAmount() == null) {
            order.setTotalAmount(order.getUnitPrice().multiply(new java.math.BigDecimal(order.getQuantity())));
        }
        
        // 保存订单
        orderMapper.insert(order);
        return order;
    }

    @Override
    public Order getOrderById(Long id) {
        return orderMapper.selectById(id);
    }

    @Override
    public List<Order> getOrdersByUserId(Long userId) {
        return orderMapper.selectByUserId(userId);
    }

    @Override
    @Transactional
    public boolean updateOrderStatus(Long orderId, String status) {
        Order order = orderMapper.selectById(orderId);
        if (order != null) {
            order.setStatus(status);
            order.setUpdateTime(java.time.LocalDateTime.now());
            return orderMapper.updateById(order) > 0;
        }
        return false;
    }

    @Override
    @Transactional
    public boolean deleteOrder(Long id) {
        return orderMapper.deleteById(id) > 0;
    }

    @Override
    public List<Order> getAllOrders() {
        return orderMapper.selectAll();
    }

    /**
     * 生成订单号
     */
    private String generateOrderNumber() {
        return "ORD" + System.currentTimeMillis() + String.format("%04d", (int)(Math.random() * 10000));
    }
}

订单Mapper接口

java 复制代码
// OrderMapper.java
package com.example.order.mapper;

import com.example.order.model.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface OrderMapper {
    
    /**
     * 插入订单
     */
    int insert(Order order);
    
    /**
     * 根据ID查询订单
     */
    Order selectById(@Param("id") Long id);
    
    /**
     * 根据用户ID查询订单
     */
    List<Order> selectByUserId(@Param("userId") Long userId);
    
    /**
     * 更新订单
     */
    int updateById(Order order);
    
    /**
     * 删除订单
     */
    int deleteById(@Param("id") Long id);
    
    /**
     * 查询所有订单
     */
    List<Order> selectAll();
}

✅ 第三部分:分布式事务业务逻辑(90分钟)

1. 订单创建事务

订单创建服务

java 复制代码
// OrderCreationService.java
package com.example.order.service;

import com.example.order.model.Order;
import com.example.order.feign.ProductFeignClient;
import com.example.order.feign.InventoryFeignClient;
import com.example.order.feign.PaymentFeignClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

@Service
public class OrderCreationService {

    @Autowired
    private OrderService orderService;
    
    @Autowired
    private ProductFeignClient productFeignClient;
    
    @Autowired
    private InventoryFeignClient inventoryFeignClient;
    
    @Autowired
    private PaymentFeignClient paymentFeignClient;

    /**
     * 创建订单(分布式事务)
     */
    @GlobalTransactional(name = "create-order-transaction", rollbackFor = Exception.class)
    public Order createOrderWithTransaction(Order order) throws Exception {
        try {
            // 1. 验证商品信息
            validateProduct(order.getProductId());
            
            // 2. 检查库存
            checkInventory(order.getProductId(), order.getQuantity());
            
            // 3. 扣减库存
            deductInventory(order.getProductId(), order.getQuantity());
            
            // 4. 创建订单
            Order createdOrder = orderService.createOrder(order);
            
            // 5. 创建支付记录
            createPaymentRecord(createdOrder);
            
            // 6. 发送订单创建通知
            sendOrderNotification(createdOrder);
            
            return createdOrder;
            
        } catch (Exception e) {
            // 分布式事务会自动回滚
            throw new RuntimeException("创建订单失败: " + e.getMessage(), e);
        }
    }

    /**
     * 验证商品信息
     */
    private void validateProduct(Long productId) {
        try {
            ProductDTO product = productFeignClient.getProduct(productId);
            if (product == null || !"ACTIVE".equals(product.getStatus())) {
                throw new RuntimeException("商品不存在或已下架");
            }
        } catch (Exception e) {
            throw new RuntimeException("验证商品信息失败: " + e.getMessage(), e);
        }
    }

    /**
     * 检查库存
     */
    private void checkInventory(Long productId, Integer quantity) {
        try {
            InventoryDTO inventory = inventoryFeignClient.getInventory(productId);
            if (inventory == null || inventory.getAvailableQuantity() < quantity) {
                throw new RuntimeException("库存不足");
            }
        } catch (Exception e) {
            throw new RuntimeException("检查库存失败: " + e.getMessage(), e);
        }
    }

    /**
     * 扣减库存
     */
    private void deductInventory(Long productId, Integer quantity) {
        try {
            boolean success = inventoryFeignClient.deductInventory(productId, quantity);
            if (!success) {
                throw new RuntimeException("扣减库存失败");
            }
        } catch (Exception e) {
            throw new RuntimeException("扣减库存失败: " + e.getMessage(), e);
        }
    }

    /**
     * 创建支付记录
     */
    private void createPaymentRecord(Order order) {
        try {
            PaymentDTO payment = new PaymentDTO();
            payment.setOrderId(order.getId());
            payment.setOrderNumber(order.getOrderNumber());
            payment.setAmount(order.getTotalAmount());
            payment.setStatus("PENDING");
            
            PaymentDTO createdPayment = paymentFeignClient.createPayment(payment);
            if (createdPayment == null) {
                throw new RuntimeException("创建支付记录失败");
            }
        } catch (Exception e) {
            throw new RuntimeException("创建支付记录失败: " + e.getMessage(), e);
        }
    }

    /**
     * 发送订单创建通知
     */
    private void sendOrderNotification(Order order) {
        try {
            NotificationDTO notification = new NotificationDTO();
            notification.setUserId(order.getUserId());
            notification.setType("ORDER_CREATED");
            notification.setTitle("订单创建成功");
            notification.setContent("您的订单 " + order.getOrderNumber() + " 已创建成功");
            
            notificationFeignClient.sendNotification(notification);
        } catch (Exception e) {
            // 通知失败不影响主流程
            log.warn("发送订单通知失败: " + e.getMessage());
        }
    }
}

2. Feign客户端接口

商品服务Feign客户端

java 复制代码
// ProductFeignClient.java
package com.example.order.feign;

import com.example.order.dto.ProductDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "product-service", fallback = ProductFeignFallback.class)
public interface ProductFeignClient {
    
    @GetMapping("/api/products/{id}")
    ProductDTO getProduct(@PathVariable("id") Long id);
}

库存服务Feign客户端

java 复制代码
// InventoryFeignClient.java
package com.example.order.feign;

import com.example.order.dto.InventoryDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(name = "inventory-service", fallback = InventoryFeignFallback.class)
public interface InventoryFeignClient {
    
    @GetMapping("/api/inventory/{productId}")
    InventoryDTO getInventory(@PathVariable("productId") Long productId);
    
    @PostMapping("/api/inventory/{productId}/deduct")
    boolean deductInventory(@PathVariable("productId") Long productId, 
                          @RequestParam("quantity") Integer quantity);
}

支付服务Feign客户端

java 复制代码
// PaymentFeignClient.java
package com.example.order.feign;

import com.example.order.dto.PaymentDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(name = "payment-service", fallback = PaymentFeignFallback.class)
public interface PaymentFeignClient {
    
    @PostMapping("/api/payments")
    PaymentDTO createPayment(@RequestBody PaymentDTO payment);
    
    @GetMapping("/api/payments/{id}")
    PaymentDTO getPayment(@PathVariable("id") Long id);
}

3. DTO类定义

商品DTO

java 复制代码
// ProductDTO.java
package com.example.order.dto;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class ProductDTO {
    
    private Long id;
    private String name;
    private String description;
    private BigDecimal price;
    private String category;
    private String status; // ACTIVE, INACTIVE, DELETED
    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    // 构造函数
    public ProductDTO() {}

    // Getter和Setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }

    public BigDecimal getPrice() { return price; }
    public void setPrice(BigDecimal price) { this.price = price; }

    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }

    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }

    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }

    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
}

库存DTO

java 复制代码
// InventoryDTO.java
package com.example.order.dto;

import java.time.LocalDateTime;

public class InventoryDTO {
    
    private Long id;
    private Long productId;
    private Integer totalQuantity;
    private Integer availableQuantity;
    private Integer reservedQuantity;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    // 构造函数
    public InventoryDTO() {}

    // Getter和Setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public Long getProductId() { return productId; }
    public void setProductId(Long productId) { this.productId = productId; }

    public Integer getTotalQuantity() { return totalQuantity; }
    public void setTotalQuantity(Integer totalQuantity) { this.totalQuantity = totalQuantity; }

    public Integer getAvailableQuantity() { return availableQuantity; }
    public void setAvailableQuantity(Integer availableQuantity) { this.availableQuantity = availableQuantity; }

    public Integer getReservedQuantity() { return reservedQuantity; }
    public void setReservedQuantity(Integer reservedQuantity) { this.reservedQuantity = reservedQuantity; }

    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }

    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
}

支付DTO

java 复制代码
// PaymentDTO.java
package com.example.order.dto;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class PaymentDTO {
    
    private Long id;
    private Long orderId;
    private String orderNumber;
    private BigDecimal amount;
    private String paymentMethod; // CREDIT_CARD, DEBIT_CARD, BANK_TRANSFER
    private String status; // PENDING, SUCCESS, FAILED, CANCELLED
    private String transactionId;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;

    // 构造函数
    public PaymentDTO() {}

    // Getter和Setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public Long getOrderId() { return orderId; }
    public void setOrderId(Long orderId) { this.orderId = orderId; }

    public String getOrderNumber() { return orderNumber; }
    public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; }

    public BigDecimal getAmount() { return amount; }
    public void setAmount(BigDecimal amount) { this.amount = amount; }

    public String getPaymentMethod() { return paymentMethod; }
    public void setPaymentMethod(String paymentMethod) { this.paymentMethod = paymentMethod; }

    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }

    public String getTransactionId() { return transactionId; }
    public void setTransactionId(String transactionId) { this.transactionId = transactionId; }

    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }

    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
}

✅ 第四部分:事务监控与异常处理(60分钟)

1. 事务监控配置

Seata监控配置

java 复制代码
// SeataMonitoringConfig.java
package com.example.order.config;

import io.seata.spring.annotation.GlobalTransactionScanner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SeataMonitoringConfig {

    @Bean
    public GlobalTransactionScanner globalTransactionScanner() {
        return new GlobalTransactionScanner("order-service", "my_test_tx_group");
    }
}

事务监控服务

java 复制代码
// TransactionMonitoringService.java
package com.example.order.service;

import io.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class TransactionMonitoringService {
    
    private static final Logger logger = LoggerFactory.getLogger(TransactionMonitoringService.class);
    
    // 事务统计信息
    private final Map<String, TransactionStats> transactionStats = new ConcurrentHashMap<>();

    /**
     * 记录事务开始
     */
    public void recordTransactionStart(String businessKey) {
        String xid = RootContext.getXID();
        if (xid != null) {
            TransactionStats stats = new TransactionStats();
            stats.setXid(xid);
            stats.setBusinessKey(businessKey);
            stats.setStartTime(System.currentTimeMillis());
            stats.setStatus("RUNNING");
            
            transactionStats.put(xid, stats);
            
            logger.info("事务开始 - XID: {}, 业务键: {}", xid, businessKey);
        }
    }

    /**
     * 记录事务提交
     */
    public void recordTransactionCommit(String xid) {
        TransactionStats stats = transactionStats.get(xid);
        if (stats != null) {
            stats.setEndTime(System.currentTimeMillis());
            stats.setStatus("COMMITTED");
            stats.setDuration(stats.getEndTime() - stats.getStartTime());
            
            logger.info("事务提交 - XID: {}, 耗时: {}ms", xid, stats.getDuration());
        }
    }

    /**
     * 记录事务回滚
     */
    public void recordTransactionRollback(String xid, String reason) {
        TransactionStats stats = transactionStats.get(xid);
        if (stats != null) {
            stats.setEndTime(System.currentTimeMillis());
            stats.setStatus("ROLLBACK");
            stats.setDuration(stats.getEndTime() - stats.getStartTime());
            stats.setRollbackReason(reason);
            
            logger.warn("事务回滚 - XID: {}, 原因: {}, 耗时: {}ms", xid, reason, stats.getDuration());
        }
    }

    /**
     * 获取事务统计信息
     */
    public Map<String, TransactionStats> getTransactionStats() {
        return new ConcurrentHashMap<>(transactionStats);
    }

    /**
     * 清理已完成的事务统计
     */
    public void cleanupCompletedTransactions() {
        transactionStats.entrySet().removeIf(entry -> {
            TransactionStats stats = entry.getValue();
            return "COMMITTED".equals(stats.getStatus()) || "ROLLBACK".equals(stats.getStatus());
        });
    }

    /**
     * 事务统计信息
     */
    public static class TransactionStats {
        private String xid;
        private String businessKey;
        private long startTime;
        private long endTime;
        private long duration;
        private String status;
        private String rollbackReason;

        // Getter和Setter方法
        public String getXid() { return xid; }
        public void setXid(String xid) { this.xid = xid; }

        public String getBusinessKey() { return businessKey; }
        public void setBusinessKey(String businessKey) { this.businessKey = businessKey; }

        public long getStartTime() { return startTime; }
        public void setStartTime(long startTime) { this.startTime = startTime; }

        public long getEndTime() { return endTime; }
        public void setEndTime(long endTime) { this.endTime = endTime; }

        public long getDuration() { return duration; }
        public void setDuration(long duration) { this.duration = duration; }

        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }

        public String getRollbackReason() { return rollbackReason; }
        public void setRollbackReason(String rollbackReason) { this.rollbackReason = rollbackReason; }
    }
}

2. 异常处理与补偿机制

分布式事务异常处理

java 复制代码
// DistributedTransactionExceptionHandler.java
package com.example.order.exception;

import com.example.order.service.TransactionMonitoringService;
import io.seata.core.context.RootContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class DistributedTransactionExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(DistributedTransactionExceptionHandler.class);
    
    @Autowired
    private TransactionMonitoringService monitoringService;

    /**
     * 处理分布式事务异常
     */
    @ExceptionHandler(Exception.class)
    public Map<String, Object> handleException(Exception e) {
        String xid = RootContext.getXID();
        
        // 记录事务回滚
        if (xid != null) {
            monitoringService.recordTransactionRollback(xid, e.getMessage());
        }
        
        logger.error("分布式事务异常 - XID: {}, 错误: {}", xid, e.getMessage(), e);
        
        Map<String, Object> response = new HashMap<>();
        response.put("success", false);
        response.put("message", "操作失败,请稍后重试");
        response.put("error", e.getMessage());
        response.put("xid", xid);
        
        return response;
    }

    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public Map<String, Object> handleBusinessException(BusinessException e) {
        String xid = RootContext.getXID();
        
        logger.warn("业务异常 - XID: {}, 错误: {}", xid, e.getMessage());
        
        Map<String, Object> response = new HashMap<>();
        response.put("success", false);
        response.put("message", e.getMessage());
        response.put("errorCode", e.getErrorCode());
        response.put("xid", xid);
        
        return response;
    }
}

业务异常类

java 复制代码
// BusinessException.java
package com.example.order.exception;

public class BusinessException extends RuntimeException {
    
    private String errorCode;
    
    public BusinessException(String message) {
        super(message);
    }
    
    public BusinessException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }
    
    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }
    
    public BusinessException(String errorCode, String message, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
    }
    
    public String getErrorCode() {
        return errorCode;
    }
    
    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }
}

🎯 今日学习总结

1. 掌握的核心技能

  • ✅ 分布式事务基础概念
  • ✅ CAP理论与BASE理论
  • ✅ Seata框架配置与使用
  • ✅ 分布式事务业务实现
  • ✅ 事务监控与异常处理

2. 分布式事务核心概念

  • 网络分区:节点间通信中断的解决方案
  • 时钟同步:逻辑时钟和向量时钟的使用
  • 数据一致性:强一致性与最终一致性
  • 服务可用性:降级策略和异步处理

3. Seata框架特点

  • AT模式:自动事务管理,对业务无侵入
  • TCC模式:手动事务控制,性能更好
  • Saga模式:长事务处理,支持补偿机制
  • XA模式:强一致性事务,性能相对较低

4. 事务监控要点

  • XID追踪:全局事务ID的生成和传播
  • 性能统计:事务执行时间和成功率
  • 异常分析:回滚原因和补偿策略
  • 资源管理:连接池和锁资源的监控

5. 下一步学习方向

  • 消息队列与异步处理
  • 分布式锁实现
  • 分布式缓存策略
  • 服务降级与熔断
  • 性能优化与调优

学习建议

  1. 理论理解:深入理解CAP理论和分布式事务的挑战
  2. 实践操作:搭建Seata环境,实现完整的分布式事务流程
  3. 异常处理:学会处理各种异常情况,实现补偿机制
  4. 性能优化:理解不同事务模式的性能特点,选择合适的模式
  5. 监控运维:学会使用监控工具分析事务性能
相关推荐
仰望星空@脚踏实地40 分钟前
maven scope 详解
java·maven·scope
M_Reus_111 小时前
Groovy集合常用简洁语法
java·开发语言·windows
带刺的坐椅1 小时前
10分钟带你体验 Solon 的状态机
java·solon·状态机·statemachine
小鹅叻1 小时前
MyBatis题
java·tomcat·mybatis
RainbowSea1 小时前
4. LangChain4j 模型参数配置超详细说明
java·langchain·ai编程
RainbowSea1 小时前
3. LangChain4j + 低阶 和 高阶 API的详细说明
java·llm·ai编程
叫我阿柒啊1 小时前
Java全栈开发面试实战:从基础到微服务的深度探索
java·spring boot·redis·微服务·vue3·全栈开发·面试技巧
ashane13141 小时前
Springboot 集成 TraceID
java·spring boot·spring
SunnyDays10111 小时前
Java PPT转多种图片格式:打造高质量的文档转换服务
java·ppt转图片·ppt转png·ppt转jpg·ppt转svg·ppt转tiff
David爱编程1 小时前
多核 CPU 下的缓存一致性问题:隐藏的性能陷阱与解决方案
java·后端