php订单日志怎么记录积分变动_php记录订单积分变化日志说明【说明】

订单创建时需在同一个数据库事务中同步写入积分变动日志,确保与订单表同库同InnoDB引擎,通过beginTransaction/commit包裹Order创建和PointLog插入,并校验before_point/after_point一致性。

订单创建时怎么同步写入积分变动日志

订单完成才触发积分发放,但日志必须在订单状态变更的**同一事务内**落库,否则会出现积分已加、日志丢失的不一致问题。PHP 中常用 beginTransaction() + commit() / rollback() 包裹订单写入和日志插入逻辑。

关键点:

  • 日志表必须与订单表同库同引擎(推荐 InnoDB),否则无法保证事务原子性
  • 不要用异步队列或定时任务补日志——延迟或失败都会导致对账困难
  • log_type 字段建议设为枚举值,如 'order_reward'(下单返积分)、'order_consume'(积分抵扣)
  • 记录原始订单 ID(order_id)、用户 ID(user_id)、变动积分值(point_change,正为增加、负为扣除)、操作前/后余额(before_point/after_point
DB::beginTransaction();
try {
    $order = Order::create($orderData);
    PointLog::create([
        'user_id'      => $order->user_id,
        'order_id'     => $order->id,
        'log_type'     => 'order_reward',
        'point_change' => $rewardPoints,
        'before_point' => $user->point,
        'after_point'  => $user->point + $rewardPoints,
        'created_at'   => now(),
    ]);
    $user->increment('point', $rewardPoints);
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
    throw $e;
}

积分抵扣订单怎么避免重复记日志

用户用积分支付时,常见错误是:前端提交两次、接口被重放、或支付回调多次通知,导致 PointLog 表出现多条相同 order_id + log_type='order_consume' 的记录。

防御措施:

  • point_log 表上建唯一索引:UNIQUE KEY `uk_order_type` (`order_id`, `log_type`)
  • 插入前先 SELECT COUNT(*) WHERE order_id = ? AND log_type = 'order_consume',存在则跳过
  • 不要依赖前端传来的积分值做计算,应以订单表中 used_point 字段为准
  • 支付回调处理必须幂等:用 ORDER BY created_at LIMIT 1 查最新订单状态,而非直接更新

怎么查某用户最近 30 天的积分变动明细

直接 SELECT * FROM point_log WHERE user_id = ? ORDER BY created_at DESC LIMIT 50 很容易慢,尤其当表数据超百万行时。

优化要点:

  • 确保有复合索引:INDEX idx_user_time (user_id, created_at)
  • 避免 SELECT *,只查必要字段,如 id, log_type, point_change, order_id, created_at
  • 如果需关联订单号展示商品信息,用应用层分批查(N+1 改成 IN 查询),别在 SQL 里 JOIN orders
  • 高频查询可加缓存,键名如 point_log:user_123:recent,TTL 设为 60 秒,避免缓存雪崩

日志表什么时候需要分表或归档

point_log 单表超过 200 万行,且 INSERTSELECT 明显变慢(慢查询日志中频繁出现),就该考虑归档。

实操建议:

  • 按月归档最稳妥:建表 point_log_202508,用 INSERT INTO ... SELECT 搬迁旧数据,再 DELETE 原表对应月份数据
  • 不要用分区表(MySQL Partitioning),维护成本高,且 Laravel/Eloquent 对分区支持弱
  • 归档后,查询“历史积分”走归档表,日常“最近变动”仍查主表,应用层路由判断
  • 归档脚本必须带事务和校验:搬完后比对 COUNT(*)SUM(point_change)

日志字段看似简单,但 before_pointafter_point 这两个值一旦因并发漏算或事务回滚没同步更新,后续所有积分对账都不可信。宁可多一次 SELECT 读当前余额,也不要靠 PHP 层变量推算。