dec9085205
- IMPL-001: 响应式编程培训方案 - IMPL-002: 敏感数据加密存储方案 - IMPL-003: 预约高峰期性能优化方案 - IMPL-004: 支付接口幂等性校验方案
742 lines
20 KiB
Markdown
742 lines
20 KiB
Markdown
# IMPL-004: 支付接口幂等性校验方案
|
||
|
||
> 文档编号: GYM-IMPL-004
|
||
> 版本: v1.0
|
||
> 日期: 2026-04-05
|
||
> 作者: 张翔
|
||
> 状态: 正式发布
|
||
|
||
---
|
||
|
||
## 文档修订历史
|
||
|
||
| 版本 | 日期 | 作者 | 修订内容 |
|
||
|------|------|------|---------|
|
||
| v1.0 | 2026-04-05 | 张翔 | 创建支付接口幂等性校验方案 |
|
||
|
||
---
|
||
|
||
## 一、需求分析
|
||
|
||
### 1.1 问题背景
|
||
|
||
支付接口缺少幂等性校验,可能导致:
|
||
- 用户重复点击支付按钮,产生多笔订单
|
||
- 网络超时重试,导致重复扣款
|
||
- 支付回调重复通知,导致订单状态异常
|
||
|
||
### 1.2 影响范围
|
||
|
||
**用户体验**:
|
||
- 重复扣款导致用户投诉
|
||
- 订单状态不一致
|
||
|
||
**财务风险**:
|
||
- 资金对账困难
|
||
- 退款流程复杂
|
||
|
||
**业务风险**:
|
||
- 订单状态不一致
|
||
- 数据完整性问题
|
||
|
||
### 1.3 成功标准
|
||
|
||
- 支付接口幂等性覆盖率100%
|
||
- 通过重复支付测试
|
||
- 通过并发支付测试
|
||
- 幂等检查性能≤10ms
|
||
|
||
---
|
||
|
||
## 二、技术方案设计
|
||
|
||
### 2.1 幂等性实现方案
|
||
|
||
#### 方案架构
|
||
|
||
```
|
||
支付请求流程:
|
||
1. 前端生成唯一订单号
|
||
2. 后端检查订单号是否已存在
|
||
3. 不存在则创建支付流水
|
||
4. 调用第三方支付
|
||
5. 支付回调处理(幂等)
|
||
6. 更新订单状态(幂等)
|
||
```
|
||
|
||
#### 核心机制
|
||
|
||
**机制1:唯一订单号**
|
||
- 格式:UUID + 时间戳 + 业务标识
|
||
- 示例:PAY-20260405-UUID-001
|
||
- 作用:全局唯一标识
|
||
|
||
**机制2:支付流水表**
|
||
- 记录所有支付请求
|
||
- 字段:流水ID、订单ID、支付单号、金额、状态、请求号
|
||
- 作用:幂等性保证
|
||
|
||
**机制3:分布式锁**
|
||
- 实现:Redis分布式锁
|
||
- 锁键:payment:lock:{requestNo}
|
||
- 作用:防止并发重复支付
|
||
|
||
**机制4:状态机**
|
||
- 订单状态流转控制
|
||
- 状态:待支付、支付中、支付成功、支付失败、取消支付
|
||
- 作用:状态一致性保证
|
||
|
||
---
|
||
|
||
### 2.2 支付状态机
|
||
|
||
#### 状态定义
|
||
|
||
```java
|
||
public enum PaymentState {
|
||
PENDING, // 待支付
|
||
PAYING, // 支付中
|
||
SUCCESS, // 支付成功
|
||
FAILED, // 支付失败
|
||
CANCELLED // 取消支付
|
||
}
|
||
```
|
||
|
||
#### 事件定义
|
||
|
||
```java
|
||
public enum PaymentEvent {
|
||
PAY, // 发起支付
|
||
SUCCESS, // 支付成功
|
||
FAIL, // 支付失败
|
||
CANCEL // 取消支付
|
||
}
|
||
```
|
||
|
||
#### 状态转换规则
|
||
|
||
```
|
||
状态转换图:
|
||
|
||
待支付 ──PAY──> 支付中 ──SUCCESS──> 支付成功
|
||
│ │
|
||
│ └──FAIL──> 支付失败
|
||
│
|
||
└──CANCEL──> 取消支付
|
||
|
||
转换规则:
|
||
- 待支付 → 支付中:发起支付
|
||
- 支付中 → 支付成功:支付成功回调
|
||
- 支付中 → 支付失败:支付失败回调
|
||
- 待支付 → 取消支付:用户取消
|
||
```
|
||
|
||
---
|
||
|
||
## 三、代码结构设计
|
||
|
||
### 3.1 包结构
|
||
|
||
```
|
||
com.gym.manage.payment/
|
||
├── idempotent/
|
||
│ ├── IdempotentService.java # 幂等性服务接口
|
||
│ ├── IdempotentServiceImpl.java # 幂等性服务实现
|
||
│ └── IdempotentAspect.java # 幂等性切面
|
||
├── statemachine/
|
||
│ ├── PaymentStateMachine.java # 支付状态机
|
||
│ ├── PaymentState.java # 支付状态
|
||
│ └── PaymentEvent.java # 支付事件
|
||
├── entity/
|
||
│ ├── PaymentFlow.java # 支付流水实体
|
||
│ └── PaymentOrder.java # 支付订单实体
|
||
├── repository/
|
||
│ ├── PaymentFlowRepository.java # 支付流水Repository
|
||
│ └── PaymentOrderRepository.java # 支付订单Repository
|
||
├── service/
|
||
│ ├── PaymentService.java # 支付服务接口
|
||
│ └── PaymentServiceImpl.java # 支付服务实现
|
||
└── controller/
|
||
└── PaymentController.java # 支付控制器
|
||
```
|
||
|
||
---
|
||
|
||
### 3.2 核心类设计
|
||
|
||
#### PaymentFlow实体
|
||
|
||
```java
|
||
@Entity
|
||
@Table(name = "payment_flow",
|
||
uniqueConstraints = @UniqueConstraint(columnNames = "requestNo"))
|
||
public class PaymentFlow {
|
||
|
||
@Id
|
||
@GeneratedValue(strategy = GenerationType.UUID)
|
||
private String flowId; // 流水ID
|
||
|
||
@Column(unique = true, nullable = false)
|
||
private String requestNo; // 请求号(幂等键)
|
||
|
||
@Column(nullable = false)
|
||
private String orderId; // 订单ID
|
||
|
||
private String paymentNo; // 支付单号
|
||
|
||
@Column(nullable = false, precision = 10, scale = 2)
|
||
private BigDecimal amount; // 支付金额
|
||
|
||
@Enumerated(EnumType.STRING)
|
||
private PaymentState state; // 支付状态
|
||
|
||
private String channel; // 支付渠道
|
||
|
||
private String errorMessage; // 错误信息
|
||
|
||
@CreatedDate
|
||
private LocalDateTime createTime; // 创建时间
|
||
|
||
@LastModifiedDate
|
||
private LocalDateTime updateTime; // 更新时间
|
||
}
|
||
```
|
||
|
||
#### IdempotentServiceImpl
|
||
|
||
```java
|
||
@Service
|
||
@Transactional
|
||
public class IdempotentServiceImpl implements IdempotentService {
|
||
|
||
@Autowired
|
||
private RedisTemplate<String, String> redisTemplate;
|
||
|
||
@Autowired
|
||
private PaymentFlowRepository flowRepository;
|
||
|
||
private static final String LOCK_PREFIX = "payment:lock:";
|
||
private static final Duration LOCK_TIMEOUT = Duration.ofMinutes(5);
|
||
|
||
@Override
|
||
public PaymentFlow checkAndCreate(String requestNo, PaymentRequest request) {
|
||
// 1. 分布式锁
|
||
String lockKey = LOCK_PREFIX + requestNo;
|
||
Boolean locked = redisTemplate.opsForValue()
|
||
.setIfAbsent(lockKey, "1", LOCK_TIMEOUT);
|
||
|
||
if (!locked) {
|
||
throw new PaymentException("支付处理中,请勿重复提交");
|
||
}
|
||
|
||
try {
|
||
// 2. 检查流水是否已存在
|
||
PaymentFlow existFlow = flowRepository
|
||
.findByRequestNo(requestNo)
|
||
.orElse(null);
|
||
|
||
if (existFlow != null) {
|
||
return existFlow; // 幂等返回
|
||
}
|
||
|
||
// 3. 创建新流水
|
||
PaymentFlow flow = new PaymentFlow();
|
||
flow.setRequestNo(requestNo);
|
||
flow.setOrderId(request.getOrderId());
|
||
flow.setAmount(request.getAmount());
|
||
flow.setState(PaymentState.PENDING);
|
||
flow.setChannel(request.getChannel());
|
||
|
||
return flowRepository.save(flow);
|
||
|
||
} finally {
|
||
redisTemplate.delete(lockKey);
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public PaymentFlow check(String requestNo) {
|
||
return flowRepository.findByRequestNo(requestNo).orElse(null);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### PaymentStateMachine
|
||
|
||
```java
|
||
@Component
|
||
public class PaymentStateMachine {
|
||
|
||
@Autowired
|
||
private PaymentOrderRepository orderRepository;
|
||
|
||
/**
|
||
* 状态转换(幂等)
|
||
*/
|
||
@Transactional
|
||
public boolean transit(String orderId, PaymentEvent event) {
|
||
PaymentOrder order = orderRepository.findById(orderId)
|
||
.orElseThrow(() -> new PaymentException("订单不存在"));
|
||
|
||
PaymentState currentState = order.getState();
|
||
|
||
// 检查状态转换是否合法
|
||
if (!canTransit(currentState, event)) {
|
||
return false; // 幂等返回
|
||
}
|
||
|
||
// 执行状态转换
|
||
PaymentState newState = getNextState(currentState, event);
|
||
order.setState(newState);
|
||
orderRepository.save(order);
|
||
|
||
return true;
|
||
}
|
||
|
||
private boolean canTransit(PaymentState current, PaymentEvent event) {
|
||
// 状态转换规则
|
||
switch (current) {
|
||
case PENDING:
|
||
return event == PaymentEvent.PAY ||
|
||
event == PaymentEvent.CANCEL;
|
||
case PAYING:
|
||
return event == PaymentEvent.SUCCESS ||
|
||
event == PaymentEvent.FAIL;
|
||
default:
|
||
return false; // 已终态,幂等返回
|
||
}
|
||
}
|
||
|
||
private PaymentState getNextState(PaymentState current, PaymentEvent event) {
|
||
switch (current) {
|
||
case PENDING:
|
||
if (event == PaymentEvent.PAY) return PaymentState.PAYING;
|
||
if (event == PaymentEvent.CANCEL) return PaymentState.CANCELLED;
|
||
break;
|
||
case PAYING:
|
||
if (event == PaymentEvent.SUCCESS) return PaymentState.SUCCESS;
|
||
if (event == PaymentEvent.FAIL) return PaymentState.FAILED;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return current;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### IdempotentAspect
|
||
|
||
```java
|
||
@Aspect
|
||
@Component
|
||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||
public class IdempotentAspect {
|
||
|
||
@Autowired
|
||
private IdempotentService idempotentService;
|
||
|
||
@Around("@annotation(idempotent)")
|
||
public Object handleIdempotent(
|
||
ProceedingJoinPoint pjp,
|
||
Idempotent idempotent
|
||
) throws Throwable {
|
||
|
||
// 1. 获取幂等键
|
||
String requestNo = extractRequestNo(pjp);
|
||
|
||
// 2. 检查幂等性
|
||
Object result = idempotentService.check(requestNo);
|
||
if (result != null) {
|
||
return result; // 幂等返回
|
||
}
|
||
|
||
// 3. 执行业务逻辑
|
||
return pjp.proceed();
|
||
}
|
||
|
||
private String extractRequestNo(ProceedingJoinPoint pjp) {
|
||
// 从方法参数中提取requestNo
|
||
Object[] args = pjp.getArgs();
|
||
for (Object arg : args) {
|
||
if (arg instanceof PaymentRequest) {
|
||
return ((PaymentRequest) arg).getRequestNo();
|
||
}
|
||
}
|
||
throw new PaymentException("未找到幂等键");
|
||
}
|
||
}
|
||
```
|
||
|
||
#### PaymentServiceImpl
|
||
|
||
```java
|
||
@Service
|
||
@Transactional
|
||
public class PaymentServiceImpl implements PaymentService {
|
||
|
||
@Autowired
|
||
private IdempotentService idempotentService;
|
||
|
||
@Autowired
|
||
private PaymentStateMachine stateMachine;
|
||
|
||
@Autowired
|
||
private PaymentFlowRepository flowRepository;
|
||
|
||
@Autowired
|
||
private ThirdPartyPaymentService thirdPartyService;
|
||
|
||
@Override
|
||
public PaymentResponse pay(PaymentRequest request) {
|
||
// 1. 幂等性检查并创建流水
|
||
PaymentFlow flow = idempotentService.checkAndCreate(
|
||
request.getRequestNo(),
|
||
request
|
||
);
|
||
|
||
// 如果流水已存在,直接返回
|
||
if (flow.getState() != PaymentState.PENDING) {
|
||
return buildResponse(flow);
|
||
}
|
||
|
||
// 2. 状态转换:待支付 → 支付中
|
||
stateMachine.transit(flow.getFlowId(), PaymentEvent.PAY);
|
||
|
||
try {
|
||
// 3. 调用第三方支付
|
||
ThirdPartyPaymentResponse response = thirdPartyService.pay(
|
||
flow.getFlowId(),
|
||
flow.getAmount()
|
||
);
|
||
|
||
// 4. 更新支付单号
|
||
flow.setPaymentNo(response.getPaymentNo());
|
||
flowRepository.save(flow);
|
||
|
||
// 5. 返回支付结果
|
||
return buildResponse(flow);
|
||
|
||
} catch (Exception e) {
|
||
// 6. 支付失败,状态转换
|
||
stateMachine.transit(flow.getFlowId(), PaymentEvent.FAIL);
|
||
flow.setErrorMessage(e.getMessage());
|
||
flowRepository.save(flow);
|
||
|
||
throw new PaymentException("支付失败", e);
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void handleCallback(PaymentCallback callback) {
|
||
// 1. 查询支付流水
|
||
PaymentFlow flow = flowRepository.findById(callback.getFlowId())
|
||
.orElseThrow(() -> new PaymentException("流水不存在"));
|
||
|
||
// 2. 幂等性检查:如果已成功,直接返回
|
||
if (flow.getState() == PaymentState.SUCCESS) {
|
||
return; // 幂等返回
|
||
}
|
||
|
||
// 3. 状态转换
|
||
PaymentEvent event = callback.isSuccess() ?
|
||
PaymentEvent.SUCCESS : PaymentEvent.FAIL;
|
||
|
||
stateMachine.transit(flow.getFlowId(), event);
|
||
|
||
// 4. 更新流水
|
||
flowRepository.save(flow);
|
||
}
|
||
|
||
private PaymentResponse buildResponse(PaymentFlow flow) {
|
||
PaymentResponse response = new PaymentResponse();
|
||
response.setFlowId(flow.getFlowId());
|
||
response.setPaymentNo(flow.getPaymentNo());
|
||
response.setState(flow.getState());
|
||
response.setAmount(flow.getAmount());
|
||
return response;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 四、测试方案
|
||
|
||
### 4.1 单元测试
|
||
|
||
#### 幂等性服务测试
|
||
|
||
```java
|
||
@SpringBootTest
|
||
@Transactional
|
||
public class IdempotentServiceTest {
|
||
|
||
@Autowired
|
||
private IdempotentService idempotentService;
|
||
|
||
@Autowired
|
||
private PaymentFlowRepository flowRepository;
|
||
|
||
@Test
|
||
public void testCheckAndCreate() {
|
||
String requestNo = "REQ-123456";
|
||
PaymentRequest request = new PaymentRequest();
|
||
request.setRequestNo(requestNo);
|
||
request.setOrderId("ORDER-001");
|
||
request.setAmount(new BigDecimal("100.00"));
|
||
|
||
// 第一次创建
|
||
PaymentFlow flow1 = idempotentService.checkAndCreate(requestNo, request);
|
||
assertNotNull(flow1);
|
||
assertEquals(PaymentState.PENDING, flow1.getState());
|
||
|
||
// 第二次创建(相同requestNo)
|
||
PaymentFlow flow2 = idempotentService.checkAndCreate(requestNo, request);
|
||
assertEquals(flow1.getFlowId(), flow2.getFlowId()); // 幂等返回
|
||
}
|
||
|
||
@Test
|
||
public void testConcurrentCreate() throws InterruptedException {
|
||
String requestNo = "REQ-789012";
|
||
int threadCount = 100;
|
||
CountDownLatch latch = new CountDownLatch(threadCount);
|
||
List<PaymentFlow> flows = Collections.synchronizedList(new ArrayList<>());
|
||
|
||
for (int i = 0; i < threadCount; i++) {
|
||
new Thread(() -> {
|
||
try {
|
||
PaymentFlow flow = idempotentService.checkAndCreate(
|
||
requestNo,
|
||
new PaymentRequest()
|
||
);
|
||
flows.add(flow);
|
||
} finally {
|
||
latch.countDown();
|
||
}
|
||
}).start();
|
||
}
|
||
|
||
latch.await();
|
||
|
||
// 验证只创建了一笔流水
|
||
assertEquals(1, flows.stream()
|
||
.map(PaymentFlow::getFlowId)
|
||
.distinct()
|
||
.count());
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 状态机测试
|
||
|
||
```java
|
||
@SpringBootTest
|
||
@Transactional
|
||
public class PaymentStateMachineTest {
|
||
|
||
@Autowired
|
||
private PaymentStateMachine stateMachine;
|
||
|
||
@Autowired
|
||
private PaymentOrderRepository orderRepository;
|
||
|
||
@Test
|
||
public void testStateTransit() {
|
||
// 创建订单
|
||
PaymentOrder order = new PaymentOrder();
|
||
order.setOrderId("ORDER-001");
|
||
order.setState(PaymentState.PENDING);
|
||
orderRepository.save(order);
|
||
|
||
// 状态转换:待支付 → 支付中
|
||
boolean result1 = stateMachine.transit("ORDER-001", PaymentEvent.PAY);
|
||
assertTrue(result1);
|
||
|
||
PaymentOrder order1 = orderRepository.findById("ORDER-001").orElse(null);
|
||
assertEquals(PaymentState.PAYING, order1.getState());
|
||
|
||
// 状态转换:支付中 → 支付成功
|
||
boolean result2 = stateMachine.transit("ORDER-001", PaymentEvent.SUCCESS);
|
||
assertTrue(result2);
|
||
|
||
PaymentOrder order2 = orderRepository.findById("ORDER-001").orElse(null);
|
||
assertEquals(PaymentState.SUCCESS, order2.getState());
|
||
|
||
// 状态转换:支付成功 → 支付失败(非法转换)
|
||
boolean result3 = stateMachine.transit("ORDER-001", PaymentEvent.FAIL);
|
||
assertFalse(result3); // 幂等返回
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4.2 集成测试
|
||
|
||
#### 完整支付流程测试
|
||
|
||
```java
|
||
@SpringBootTest
|
||
@Transactional
|
||
public class PaymentIntegrationTest {
|
||
|
||
@Autowired
|
||
private PaymentService paymentService;
|
||
|
||
@Autowired
|
||
private PaymentFlowRepository flowRepository;
|
||
|
||
@Test
|
||
public void testCompletePaymentFlow() {
|
||
// 1. 发起支付
|
||
PaymentRequest request = new PaymentRequest();
|
||
request.setRequestNo("REQ-001");
|
||
request.setOrderId("ORDER-001");
|
||
request.setAmount(new BigDecimal("100.00"));
|
||
|
||
PaymentResponse response = paymentService.pay(request);
|
||
assertNotNull(response.getFlowId());
|
||
assertEquals(PaymentState.PAYING, response.getState());
|
||
|
||
// 2. 模拟支付成功回调
|
||
PaymentCallback callback = new PaymentCallback();
|
||
callback.setFlowId(response.getFlowId());
|
||
callback.setSuccess(true);
|
||
|
||
paymentService.handleCallback(callback);
|
||
|
||
// 3. 验证流水状态
|
||
PaymentFlow flow = flowRepository.findById(response.getFlowId()).orElse(null);
|
||
assertEquals(PaymentState.SUCCESS, flow.getState());
|
||
}
|
||
|
||
@Test
|
||
public void testDuplicatePayment() {
|
||
String requestNo = "REQ-002";
|
||
|
||
// 第一次支付
|
||
PaymentRequest request = new PaymentRequest();
|
||
request.setRequestNo(requestNo);
|
||
request.setOrderId("ORDER-002");
|
||
request.setAmount(new BigDecimal("100.00"));
|
||
|
||
PaymentResponse response1 = paymentService.pay(request);
|
||
|
||
// 第二次支付(相同requestNo)
|
||
PaymentResponse response2 = paymentService.pay(request);
|
||
|
||
// 验证幂等性
|
||
assertEquals(response1.getFlowId(), response2.getFlowId());
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4.3 压力测试
|
||
|
||
#### 并发支付测试
|
||
|
||
```java
|
||
@SpringBootTest
|
||
public class PaymentConcurrencyTest {
|
||
|
||
@Autowired
|
||
private PaymentService paymentService;
|
||
|
||
@Autowired
|
||
private PaymentFlowRepository flowRepository;
|
||
|
||
@Test
|
||
public void testConcurrentPayment() throws InterruptedException {
|
||
int threadCount = 100;
|
||
CountDownLatch latch = new CountDownLatch(threadCount);
|
||
String requestNo = "REQ-CONCURRENT-001";
|
||
|
||
for (int i = 0; i < threadCount; i++) {
|
||
new Thread(() -> {
|
||
try {
|
||
PaymentRequest request = new PaymentRequest();
|
||
request.setRequestNo(requestNo);
|
||
request.setOrderId("ORDER-CONCURRENT-001");
|
||
request.setAmount(new BigDecimal("100.00"));
|
||
|
||
paymentService.pay(request);
|
||
} finally {
|
||
latch.countDown();
|
||
}
|
||
}).start();
|
||
}
|
||
|
||
latch.await();
|
||
|
||
// 验证只创建了一笔支付流水
|
||
List<PaymentFlow> flows = flowRepository.findByRequestNo(requestNo);
|
||
assertEquals(1, flows.size());
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、实施步骤
|
||
|
||
| 步骤 | 任务 | 负责人 | 完成时间 | 验收标准 |
|
||
|------|------|--------|---------|---------|
|
||
| 1 | 设计幂等性方案 | 架构师 | 1天 | 方案文档完成 |
|
||
| 2 | 创建支付流水表 | 后端开发 | 1天 | 数据库表创建完成 |
|
||
| 3 | 实现幂等性服务 | 后端开发 | 2天 | 单元测试通过 |
|
||
| 4 | 实现状态机 | 后端开发 | 1天 | 单元测试通过 |
|
||
| 5 | 实现幂等性切面 | 后端开发 | 1天 | 单元测试通过 |
|
||
| 6 | 单元测试 | 后端开发 | 1天 | 单元测试通过 |
|
||
| 7 | 集成测试 | 测试工程师 | 1天 | 集成测试通过 |
|
||
| 8 | 压力测试 | 测试工程师 | 1天 | 性能指标达标 |
|
||
|
||
---
|
||
|
||
## 六、验收标准
|
||
|
||
### 6.1 功能验收
|
||
|
||
- [ ] 支付接口幂等性覆盖率100%
|
||
- [ ] 通过重复支付测试
|
||
- [ ] 通过并发支付测试
|
||
- [ ] 支付回调幂等处理
|
||
|
||
### 6.2 性能验收
|
||
|
||
- [ ] 幂等检查性能≤10ms
|
||
- [ ] 分布式锁获取≤5ms
|
||
|
||
### 6.3 安全验收
|
||
|
||
- [ ] 无重复扣款风险
|
||
- [ ] 订单状态一致性保证
|
||
|
||
---
|
||
|
||
## 七、风险与应对
|
||
|
||
### 7.1 风险识别
|
||
|
||
**风险1:分布式锁失效**
|
||
- 应对:数据库唯一索引兜底
|
||
|
||
**风险2:状态机死锁**
|
||
- 应对:超时自动释放 + 监控告警
|
||
|
||
**风险3:支付流水表过大**
|
||
- 应对:定期归档历史流水
|
||
|
||
**风险4:第三方支付重复回调**
|
||
- 应对:幂等处理 + 幂等键去重
|
||
|
||
---
|
||
|
||
## 八、相关文档
|
||
|
||
- [改进路线图](../05-PLANS/改进路线图.md)
|
||
- [EVAL-003-安全性与容错能力评估报告](../03-EVALUATION/EVAL-003-安全性与容错能力评估报告.md)
|
||
- [SEC-安全设计](../02-ARCHITECTURE/技术架构/SEC-安全设计.md)
|