Files
monisuo/EMERGENCY_BALANCE_FIX.md

322 lines
7.6 KiB
Markdown
Raw Normal View History

# 充值审批余额未更新 - 紧急诊断和修复方案
**问题**: 充值审批成功后,用户资金账户余额没有增加
**紧急程度**: 🔴 高危
**时间**: 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分钟