文档目录
钱包账户表

简介

本文件面向电商开发者,系统化梳理 DouPHP 系统中“用户钱包”相关的数据模型与业务流程,重点覆盖:

  • 钱包账户表(dou_user_wallet):用户ID、可用余额、冻结金额、累计消费、累计推广收益等核心字段设计。
  • 余额流水表(dou_money):作为权威账本,记录所有余额变动明细,包含来源/去向、动作类型、关联业务单号等。
  • 充值记录(recharge):通过 dou_money.source_type/source_id 与订单/充值包入账关联,形成可追溯的充值链路。
  • 提现记录表(dou_withdraw):字段设计与申请、审核、打款、驳回全流程。
  • 资金安全保障、余额一致性校验、并发控制等技术方案。

项目结构与范围

围绕钱包功能,涉及的核心模块与文件包括:

  • 用户钱包快照表定义与初始化逻辑
  • 余额/积分流水写入与快照更新
  • 提现申请、审核、打款流程
  • 余额流水表的扩展字段与索引优化
  • 提现状态机与历史数据迁移
graph TB
A["用户中心<br/>dou_user_wallet"] --> B["余额流水<br/>dou_money"]
C["提现记录<br/>dou_withdraw"] --> B
D["订单/充值包<br/>order / money_package"] --> B
E["支付完成事件<br/>order.paid.money"] --> B
F["管理员审核<br/>admin.withdraw.*"] --> C

核心数据模型

本节聚焦钱包相关的三张核心表:用户钱包快照表、余额流水表、提现记录表。

用户钱包快照表(dou_user_wallet)

  • 作用:以 user_id 为主键的账户视图聚合缓存,提供快速读取的余额、冻结、积分、累计消费、累计推广收益等指标。
  • 关键字段说明:
    • id:会员ID(主键)
    • money_balance:可用余额(decimal(12,2))
    • money_freeze:冻结金额(decimal(12,2))
    • point_balance:可用积分(int)
    • point_freeze:冻结积分(int)
    • total_consumption:累计消费(decimal(12,2))
    • total_promote:累计推广收益(decimal(12,2))
    • updated_at:更新时间
  • 设计要点:
    • 该表为“快照/视图”,权威账本在 dou_money/dou_point;当余额/积分发生变动时,由服务层同步更新此表,保证最终一致。
    • 首次写入采用 upsert 策略,缺省值兜底,避免空行导致查询异常。

余额流水表(dou_money)

  • 作用:不可篡改的权威账本,记录每一笔余额增减,支持按用户、动作、来源等多维度审计与对账。
  • 关键扩展字段(来自升级脚本):
    • operator_type/operator_id:操作者类型与ID(admin/user/work/system),替代旧 work_id/admin_id,便于多角色记账。
    • source_type/source_id:业务来源类型与主键(如 order_pay/order_refund/recharge/withdraw),用于跨模块溯源。
    • from_user_id:来源用户ID(用于分销、返利等场景)。
    • ip:来源IP(兼容IPv6)。
    • created_at:统一时间字段(替代 create_time)。
  • 索引优化:
    • idx_user(user_id, action):提升按用户+动作查询效率。
    • idx_from_user(from_user_id):提升来源用户维度统计。
    • idx_operator(operator_type, operator_id):提升操作者维度审计。
    • idx_source(source_type, source_id):提升业务来源溯源查询。

提现记录表(dou_withdraw)

  • 作用:记录用户提现申请及处理过程,支撑审核、打款、驳回等流程。
  • 关键字段说明:
    • withdraw_sn:提现单号(唯一)
    • user_id:会员ID
    • money:提现金额
    • card_number/card_bank/card_name:收款银行卡信息
    • card_status:收款记录标记(0未到账/1已到账)
    • handle_record:处理记录
    • handled_at:处理时间
    • status:提现状态(字符串化:pending/approved/paid/rejected)
    • created_at:申请时间
  • 索引:
    • 主键 id
    • 唯一索引 withdraw_sn
    • 复合索引 idx_user(user_id, status):提升按用户+状态的查询

架构总览

钱包系统以“流水优先、快照辅助”的设计原则构建:

  • 所有余额变动必须落库到 dou_money,确保可审计、可回溯。
  • dou_user_wallet 作为高性能读侧快照,由服务层在写侧同步更新。
  • 提现流程通过 dou_withdraw 记录申请与处理,结合状态机管理生命周期。
  • 充值入账通过 dou_money.source_type/source_id 与订单/充值包关联,形成完整资金链路。
sequenceDiagram
participant U as "用户"
participant WS as "提现服务(WalletService)"
participant M as "余额流水(dou_money)"
participant W as "提现记录(dou_withdraw)"
participant S as "用户钱包快照(dou_user_wallet)"
U->>WS : 提交提现申请
WS->>W : 创建提现记录(状态=pending)
WS->>M : 扣减余额(负数),计算新total
M-->>WS : 写入成功
WS->>S : 更新money_balance快照
WS-->>U : 返回申请成功

详细组件分析

用户钱包快照(dou_user_wallet)

  • 设计目标:提供 O(1) 读取的余额/积分/累计指标,降低高并发读压力。
  • 更新策略:
    • 每次余额/积分变动后,调用 upsertWallet 更新快照,缺失字段使用默认值。
    • 针对推广收益(direct_reward/indirect_reward)正增长时,同步累加 total_promote。
  • 一致性保障:
    • 以 dou_money/dou_point 为准,快照仅做加速读;若出现不一致,可通过重算任务修复。

余额流水(dou_money)

  • 写入流程:
    • 先以 FOR UPDATE 锁定最新 total,再计算新 total 并插入流水。
    • 若 total &lt; 0 则拒绝写入,防止透支。
  • 溯源能力:
    • source_type/source_id 将余额变动与具体业务单绑定(如 recharge、withdraw、order_pay)。
    • operator_type/operator_id 区分操作主体(管理员、用户、系统、员工)。
  • 索引优化:
    • 按 user_id/action、from_user_id、operator、source 建立复合索引,提升常见查询性能。

提现流程(dou_withdraw)

  • 申请阶段:
    • 生成唯一提现单号,写入 dou_withdraw(status=pending)。
    • 立即扣减用户余额(通过 WalletService.createMoney),并记录流水。
  • 审核阶段:
    • 后台服务负责列表筛选、详情组装、处理记录、卡信息解锁等。
  • 状态机:
    • pending → approved → paid(终态)
    • pending → rejected(终态)
    • 历史 tinyint 状态已迁移为字符串,保证可读性与可扩展性。
flowchart TD
Start(["开始"]) --> Apply["创建提现记录<br/>status=pending"]
Apply --> Deduct["扣减余额<br/>写入dou_money"]
Deduct --> UpdateSnapshot["更新用户钱包快照"]
UpdateSnapshot --> Review{"管理员审核"}
Review --> |通过| Approve["状态=approved"]
Review --> |驳回| Reject["状态=rejected"]
Approve --> Pay["线下打款完成"]
Pay --> Paid["状态=paid"]
Reject --> End(["结束"])
Paid --> End

充值入账(recharge)

  • 充值入账通过 dou_money.source_type='recharge' 与 source_id 关联订单或充值包,形成可追溯的充值链路。
  • 订单支付成功后,系统通过事件触发充值包入账,避免重复入账(基于订单号防重)。
  • 余额快照同步更新,确保前端展示与后台统计一致。

依赖关系分析

  • 提现服务依赖:
    • WalletService:负责余额流水写入与快照更新。
    • UserStatsService:获取用户总余额用于校验。
    • Withdraw 模型:持久化提现记录。
  • 状态机依赖:
    • WithdrawStatus:定义合法状态与迁移规则,贯穿前后端展示与处理逻辑。
  • 索引与查询:
    • 通过复合索引提升按用户、状态、来源等维度的查询性能。
classDiagram
class WalletService {
+createMoney(...)
+upsertWallet(...)
}
class WithdrawService_Front {
+applyWithdraw(...)
+buildWithdrawApplyData(...)
}
class WithdrawService_Admin {
+showDetail(...)
}
class WithdrawStatus {
+PENDING
+APPROVED
+PAID
+REJECTED
}
WithdrawService_Front --> WalletService : "扣款/记账"
WithdrawService_Admin --> WithdrawStatus : "状态判断"
WithdrawService_Front --> WithdrawStatus : "状态展示"

性能与并发控制

  • 并发安全:
    • 余额写入使用 FOR UPDATE 行锁,确保在高并发下 total 计算正确,避免竞态条件。
  • 索引优化:
    • 针对高频查询建立复合索引(user_id/action、from_user_id、operator、source),减少全表扫描。
  • 读写分离建议:
    • 读侧优先使用 dou_user_wallet 快照;写侧严格走 dou_money 流水。
  • 幂等与去重:
    • 充值包入账基于订单号防重,避免重复入账。
    • 提现单号唯一约束,防止重复申请。

资金安全与一致性校验

  • 余额一致性:
    • 任何余额变动必须写入 dou_money,并通过 upsertWallet 更新快照,保证最终一致。
    • 若发现不一致,可通过重算任务基于流水重新计算快照。
  • 提现风控:
    • 申请前校验待审核笔数、金额上限、银行卡必填等。
    • 申请成立即扣款,状态为 pending,等待审核。
  • 状态机约束:
    • 使用 WithdrawStatus 定义合法迁移,避免非法状态跳转。
  • 审计与溯源:
    • operator_type/operator_id、source_type/source_id 提供完整审计线索。
    • 提现记录包含处理记录与处理时间,便于问题定位。

故障排查指南

  • 常见问题:
    • 提现申请失败:检查是否已有待审核记录、金额是否为正、是否超过可用余额。
    • 余额不一致:核对 dou_money 最新流水与 dou_user_wallet 快照,必要时执行重算。
    • 充值重复入账:确认 source_type/source_id 是否唯一,检查订单号防重逻辑。
  • 定位方法:
    • 通过 source_type/source_id 追溯到具体业务单。
    • 通过 operator_type/operator_id 定位操作主体。
    • 查看提现记录的 handle_record 与 handled_at,确认处理轨迹。

结论

DouPHP 的钱包体系以“流水优先、快照辅助”为核心,通过严谨的状态机与索引优化,实现了高并发下的资金安全与一致性。开发者在扩展充值、提现、分销等功能时,应遵循以下原则:

  • 所有余额变动必须写入 dou_money,并同步更新 dou_user_wallet。
  • 使用 source_type/source_id 进行业务溯源,确保可审计。
  • 借助 WithdrawStatus 管理提现状态,避免非法跳转。
  • 利用复合索引提升查询性能,结合行锁保障并发安全。
添加日期:2026-10-05