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. 分销订单创建失败不影响支付,但需要后续手动补偿
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**修复完成!请重启后端服务并测试。**
|