Files
monisuo/EMERGENCY_BALANCE_FIX.md
sion fb7bef6424 docs: 添加充值审批余额验证工具和紧急修复文档
新增文件:
1. EMERGENCY_BALANCE_FIX.md - 充值审批余额未更新的紧急修复方案
2. verify_balance.sh - 自动化余额验证脚本

改进内容:
- 添加详细的诊断步骤
- 添加数据库验证SQL
- 添加日志检查方法
- 添加服务重启指南

这些工具用于帮助诊断和修复充值审批后资金账户余额未更新的问题
2026-03-24 11:54:24 +08:00

322 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 充值审批余额未更新 - 紧急诊断和修复方案
**问题**: 充值审批成功后,用户资金账户余额没有增加
**紧急程度**: 🔴 高危
**时间**: 2026-03-24 11:45
---
## 🚨 立即检查清单
### 1. 服务是否重启?(最可能的原因)
```bash
# 检查服务运行时间
ps -p $(pgrep -f monisuo-1.0.jar) -o lstart,etime
# 如果运行时间早于代码提交时间,说明没有重启
# 代码提交时间: 2026-03-24 11:36
# 如果服务运行时间早于这个时间,必须重启!
```
**重启服务**:
```bash
# 停止旧服务
pkill -f "monisuo-1.0.jar"
# 启动新服务
cd ~/Desktop/projects/monisuo
nohup java -jar target/monisuo-1.0.jar > logs/spring.log 2>&1 &
# 查看日志
tail -f logs/spring.log
```
---
### 2. 查看审批日志
```bash
# 查找最近的审批日志
grep -A30 "充值审批成功" logs/spring.log | tail -50
# 应该看到:
# ✅ [FundService.approve] 步骤4: 处理充值通过...
# ✅ 审批前余额: 0.00
# ✅ 准备更新账户余额: 100.00
# ✅ 执行 SQL UPDATE (使用 LambdaUpdateWrapper)...
# ✅ 账户更新结果: 1 (1=成功, 0=失败)
# ✅ 验证更新后余额: 100.00
# ✅ [充值审批成功] ...
```
---
### 3. 数据库验证
```sql
-- 1. 查询订单状态
SELECT order_no, user_id, amount, status, approve_time
FROM order_fund
WHERE order_no = '订单号';
-- 2. 查询账户余额(关键!)
SELECT user_id, balance, total_deposit, update_time
FROM account_fund
WHERE user_id = [ID];
-- 3. 查询流水记录
SELECT * FROM account_flow
WHERE related_order_no = '订单号'
ORDER BY create_time DESC;
-- 4. 如果余额未更新,手动更新(临时方案)
UPDATE account_fund
SET balance = balance + [],
total_deposit = total_deposit + [],
update_time = NOW()
WHERE user_id = [ID];
```
---
## 🔍 问题分析
### 当前代码逻辑(已修复版本)
```java
// FundService.approve() - 充值审批通过
if (order.getType() == 1 && status == 2) {
// 1. 计算新余额
BigDecimal newBalance = fund.getBalance().add(order.getAmount());
BigDecimal newTotalDeposit = fund.getTotalDeposit().add(order.getAmount());
// 2. 使用 LambdaUpdateWrapper 显式更新
LambdaUpdateWrapper<AccountFund> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(AccountFund::getId, fund.getId())
.set(AccountFund::getBalance, newBalance)
.set(AccountFund::getTotalDeposit, newTotalDeposit)
.set(AccountFund::getUpdateTime, LocalDateTime.now());
// 3. 执行更新
int updateResult = accountFundMapper.update(null, wrapper);
// 4. 验证更新
if (updateResult <= 0) {
throw new RuntimeException("充值审批更新账户余额失败");
}
// 5. 再次查询验证
AccountFund verifyFund = accountFundMapper.selectById(fund.getId());
if (!verifyFund.getBalance().equals(newBalance)) {
throw new RuntimeException("余额更新失败");
}
// 6. 记录流水
assetService.createFlow(userId, 1, amount, balanceBefore, newBalance, "USDT", orderNo, "充值");
}
```
### 可能的问题点
#### 问题1: 服务未重启 ⭐⭐⭐⭐⭐
**症状**: 代码已修改,但服务还在运行旧版本
**原因**: Java 应用需要重启才能加载新代码
**解决**: 重启服务
#### 问题2: 事务回滚
**症状**: 日志显示更新成功,但数据库未变化
**原因**: 事务在后续步骤失败并回滚
**验证**: 查看日志是否有异常
**解决**: 修复后续步骤的错误
#### 问题3: 查询错误账户
**症状**: 更新了账户,但查询的是另一个账户
**原因**: user_id 不匹配
**验证**: 检查订单的 user_id 和账户的 user_id
**解决**: 确保查询条件正确
#### 问题4: MyBatis 缓存
**症状**: 数据库已更新,但查询返回旧数据
**原因**: MyBatis 一级缓存或二级缓存
**解决**: 清除缓存或禁用缓存
---
## 🔧 修复方案
### 方案 A: 立即重启服务(推荐)
```bash
cd ~/Desktop/projects/monisuo
pkill -f "monisuo-1.0.jar"
nohup java -jar target/monisuo-1.0.jar > logs/spring.log 2>&1 &
```
**验证**:
1. 执行一次充值审批
2. 查看日志是否有"账户更新结果: 1"
3. 查询数据库确认余额增加
---
### 方案 B: 添加强制清除缓存
修改 `FundService.approve()`:
```java
// 在方法开始添加
@Autowired
private SqlSession sqlSession;
@Transactional
public void approve(...) {
// 强制清除 MyBatis 缓存
sqlSession.clearCache();
// ... 原有逻辑
}
```
---
### 方案 C: 添加最终验证和重试
`FundService.approve()` 方法最后添加:
```java
// 在方法最后添加最终验证
AccountFund finalFund = accountFundMapper.selectById(fund.getId());
System.out.println("[最终验证] 数据库实际余额: " + finalFund.getBalance());
if (!finalFund.getBalance().equals(newBalance)) {
System.err.println("[严重错误] 余额更新失败!");
System.err.println(" - 期望余额: " + newBalance);
System.err.println(" - 实际余额: " + finalFund.getBalance());
// 尝试再次更新
int retryResult = accountFundMapper.update(null, wrapper);
System.out.println("[重试更新] 结果: " + retryResult);
if (retryResult <= 0) {
throw new RuntimeException("余额更新失败,事务将回滚");
}
}
```
---
### 方案 D: 检查事务配置
确认 `SpcCloudApplication.java` 是否有 `@EnableTransactionManagement`:
```java
@SpringBootApplication
@EnableTransactionManagement // ⭐ 必须有这个
public class SpcCloudApplication {
// ...
}
```
---
## 📊 验证脚本
使用我创建的验证脚本:
```bash
chmod +x ~/Desktop/projects/monisuo/verify_balance.sh
./verify_balance.sh
```
---
## 🎯 执行步骤
### 步骤1: 立即重启服务
```bash
cd ~/Desktop/projects/monisuo
pkill -f "monisuo-1.0.jar"
nohup java -jar target/monisuo-1.0.jar > logs/spring.log 2>&1 &
```
### 步骤2: 测试审批
1. 登录管理后台
2. 进入"订单管理" -> "待审批订单"
3. 选择一个充值订单
4. 点击"审批通过"
5. **不要关闭页面**
### 步骤3: 立即查看日志
```bash
tail -f logs/spring.log | grep -A20 "FundService.approve"
```
**应该看到**:
```
[FundService.approve] 步骤4: 处理充值通过...
- 审批前余额: 0.00
- 准备更新账户余额: 100.00
- 执行 SQL UPDATE (使用 LambdaUpdateWrapper)...
- 账户更新结果: 1 (1=成功, 0=失败) <-- 必须是 1
- 验证更新后余额: 100.00
[充值审批成功] 订单号: xxx, 充值金额: 100 USDT
```
### 步骤4: 数据库验证
```sql
-- 查询订单状态应该是3
SELECT order_no, status, approve_time FROM order_fund WHERE order_no = '订单号';
-- 查询账户余额(应该增加了)
SELECT user_id, balance, total_deposit FROM account_fund WHERE user_id = [ID];
-- 查询流水记录(应该有记录)
SELECT * FROM account_flow WHERE related_order_no = '订单号';
```
---
## ❌ 如果问题依然存在
提供以下信息:
1. **服务启动时间**
```bash
ps -p $(pgrep -f monisuo-1.0.jar) -o lstart
```
2. **完整审批日志**
```bash
grep -A50 "审批订单开始" logs/spring.log | tail -60
```
3. **数据库查询结果**
```sql
-- 订单信息
SELECT * FROM order_fund WHERE order_no = '订单号';
-- 账户信息
SELECT * FROM account_fund WHERE user_id = [ID];
-- 流水记录
SELECT * FROM account_flow WHERE related_order_no = '订单号';
```
4. **事务日志**
```bash
grep -i "transaction\|rollback\|commit" logs/spring.log | tail -20
```
---
**最后更新**: 2026-03-24 11:45
**状态**: 等待重启服务并测试
**预期修复时间**: 5分钟