161 lines
4.8 KiB
Markdown
161 lines
4.8 KiB
Markdown
# ✅ 支付事务回滚问题修复完成
|
||
|
||
**修复时间:** 2026-01-25
|
||
**问题:** 订单支付时出现 "Transaction rolled back because it has been marked as rollback-only" 错误
|
||
|
||
---
|
||
|
||
## 🔍 问题分析
|
||
|
||
### 错误现象
|
||
```
|
||
支付失败: Transaction rolled back because it has been marked as rollback-only
|
||
```
|
||
|
||
### 根本原因
|
||
在 `OrderServiceImpl.payOrder()` 方法中,调用了 `distributorService.createDistributorOrderFromOrder(order)`,该方法内部可能抛出异常,导致外层事务被标记为 rollback-only。
|
||
|
||
虽然代码中有 try-catch 包裹,但由于事务传播机制的问题,内部事务的异常仍然会影响外层事务。
|
||
|
||
---
|
||
|
||
## 🔧 修复方案
|
||
|
||
### 修复1:增强异常日志
|
||
在 `OrderServiceImpl.payOrder()` 中增加了更详细的日志输出:
|
||
|
||
```java
|
||
// ✅ 新增:订单支付成功后,自动创建分销订单记录
|
||
// 🔥 修复:使用独立事务,避免影响主支付流程
|
||
try {
|
||
log.info("订单支付成功,开始创建分销订单记录...");
|
||
log.info("订单信息: orderId={}, userId={}, serviceId={}, serviceType={}, payAmount={}",
|
||
order.getId(), order.getUserId(), order.getServiceId(), order.getServiceType(), order.getPayAmount());
|
||
distributorService.createDistributorOrderFromOrder(order);
|
||
log.info("✅ 分销订单记录创建完成");
|
||
} catch (Exception e) {
|
||
log.error("❌ 创建分销订单记录失败: orderId={}, error={}", order.getId(), e.getMessage(), e);
|
||
// 🔥 关键:不影响支付流程,只记录错误
|
||
// 即使分销订单创建失败,支付也应该成功
|
||
}
|
||
```
|
||
|
||
### 修复2:使用独立事务(REQUIRES_NEW)
|
||
将 `DistributorServiceImpl.createDistributorOrderFromOrder()` 方法改为使用独立事务:
|
||
|
||
```java
|
||
@Override
|
||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||
public void createDistributorOrderFromOrder(com.peidu.entity.Order order) {
|
||
log.info("=== 开始创建分销订单记录(独立事务) ===");
|
||
// ... 业务逻辑
|
||
}
|
||
```
|
||
|
||
**关键点:**
|
||
- `Propagation.REQUIRES_NEW` 会创建一个新的独立事务
|
||
- 即使这个事务失败回滚,也不会影响外层的支付事务
|
||
- 外层的 try-catch 会捕获异常,但不会导致支付失败
|
||
|
||
### 修复3:添加必要的import
|
||
在 `DistributorServiceImpl` 中添加了缺失的import:
|
||
|
||
```java
|
||
import org.springframework.transaction.annotation.Propagation;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 修复结果
|
||
|
||
### 编译状态
|
||
```
|
||
[INFO] BUILD SUCCESS
|
||
[INFO] Total time: 24.136 s
|
||
```
|
||
|
||
### 修改的文件
|
||
1. `peidu/backend/src/main/java/com/peidu/service/impl/OrderServiceImpl.java`
|
||
2. `peidu/backend/src/main/java/com/peidu/service/impl/DistributorServiceImpl.java`
|
||
|
||
---
|
||
|
||
## 🧪 测试步骤
|
||
|
||
### 1. 重启后端服务
|
||
```bash
|
||
# 停止当前运行的后端服务
|
||
# 重新启动后端服务
|
||
```
|
||
|
||
### 2. 测试支付功能
|
||
1. 打开小程序,进入订单详情页面
|
||
2. 点击"支付"按钮
|
||
3. 选择支付方式(mock模拟支付)
|
||
4. 观察支付结果
|
||
|
||
### 3. 预期结果
|
||
- ✅ 支付成功
|
||
- ✅ 订单状态更新为"已支付"
|
||
- ✅ 即使分销订单创建失败,支付也能成功
|
||
- ✅ 后端日志中会记录详细的支付流程信息
|
||
|
||
### 4. 查看后端日志
|
||
关注以下日志输出:
|
||
```
|
||
=== 开始处理支付 ===
|
||
订单ID: xxx
|
||
支付方式: mock
|
||
订单当前状态: 0
|
||
状态验证通过,开始更新订单
|
||
准备更新数据库...
|
||
数据库更新结果: true
|
||
支付成功,订单状态已更新为: 1
|
||
订单支付成功,开始创建分销订单记录...
|
||
订单信息: orderId=xxx, userId=xxx, serviceId=xxx, serviceType=xxx, payAmount=xxx
|
||
✅ 分销订单记录创建完成
|
||
=== 支付处理完成,返回结果: true ===
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 技术说明
|
||
|
||
### 事务传播机制
|
||
|
||
**REQUIRED(默认):**
|
||
- 如果当前存在事务,加入该事务
|
||
- 如果内部方法抛出异常,会标记外层事务为 rollback-only
|
||
|
||
**REQUIRES_NEW:**
|
||
- 总是创建新事务
|
||
- 挂起当前事务(如果存在)
|
||
- 新事务独立提交或回滚,不影响外层事务
|
||
|
||
### 为什么这样修复有效?
|
||
|
||
1. **独立事务隔离**:分销订单创建使用独立事务,失败不影响支付
|
||
2. **异常捕获**:外层 try-catch 捕获异常,记录日志但不抛出
|
||
3. **业务解耦**:支付成功与否不依赖分销订单创建
|
||
|
||
---
|
||
|
||
## 🎯 后续优化建议
|
||
|
||
1. **异步处理**:将分销订单创建改为异步处理(使用消息队列)
|
||
2. **重试机制**:分销订单创建失败时,可以加入重试队列
|
||
3. **监控告警**:分销订单创建失败时发送告警通知
|
||
|
||
---
|
||
|
||
## 📌 注意事项
|
||
|
||
1. 重启后端服务后才能生效
|
||
2. 如果仍然失败,查看后端日志找出具体原因
|
||
3. 分销订单创建失败不影响支付,但需要后续手动补偿
|
||
|
||
---
|
||
|
||
**修复完成!请重启后端服务并测试。**
|