You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中JSON存储用户活动:多用户大文件场景旧记录丢失求助

问题分析与修复方案

你现在的问题核心出在两点:

  1. 当前用Storage::append写入的不是标准JSON数组,只是每行一个独立JSON对象——如果后续有代码尝试将这些行整合成标准JSON数组(比如读取全部内容后重新编码写入),多用户并发时必然会出现覆盖,导致旧记录丢失。
  2. 即便不做数组转换,当文件体积过大时,部分文件系统的追加操作可能因缓存或并发冲突出现数据丢失。

方案1:改用JSON Lines格式(推荐,无并发覆盖风险)

这种格式允许每行存储一个独立的JSON对象,写入时直接追加,读取时逐行解析,天然支持并发写入,无需复杂锁机制。

修改appendToLog方法:

protected function appendToLog($activity)
{
    $logFile = 'activity.jsonl'; // 用.jsonl后缀明确标识格式,避免混淆标准JSON
    // 确保每个JSON对象是单行,防止换行符破坏结构
    $log = json_encode($activity, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL;
    Storage::append($logFile, $log);
}

读取日志时的处理方式:

$lines = Storage::lines('activity.jsonl');
$activities = array_map(fn($line) => json_decode($line, true), $lines);

方案2:标准JSON数组+文件锁(适合必须用数组的场景)

如果一定要保持文件为标准JSON数组,必须在读写时加排他锁,阻止并发操作导致的覆盖。

修改appendToLog方法:

protected function appendToLog($activity)
{
    $logFile = storage_path('app/activity.json'); // 用绝对路径确保锁能正确生效
    $handle = fopen($logFile, 'c+'); // 打开文件,不存在则自动创建

    if (flock($handle, LOCK_EX)) { // 获取排他锁,同一时间仅一个进程可写入
        fseek($handle, 0, SEEK_END); // 跳转至文件末尾
        $fileSize = ftell($handle);

        if ($fileSize === 0) {
            // 文件为空时,直接写入包含第一个元素的数组
            fwrite($handle, json_encode([$activity], JSON_PRETTY_PRINT));
        } else {
            // 移除文件末尾的闭合符"]",追加新元素后补回闭合符
            fseek($handle, -1, SEEK_END);
            fwrite($handle, ',' . PHP_EOL . '    ' . json_encode($activity, JSON_PRETTY_PRINT) . ']');
        }

        flock($handle, LOCK_UN); // 释放锁,允许其他进程操作
    }

    fclose($handle);
}

注意事项:

  • 用storage_path获取绝对路径,避免Laravel Storage封装带来的路径歧义,保证锁的有效性。
  • JSON_PRETTY_PRINT用于维持格式可读性,不需要可以直接删除。
  • 该方式在高并发场景下会有性能损耗,因为锁会让写入操作串行化。

额外建议

不要用JSON文件存储大量日志,当记录量达到一定规模后性能会急剧下降,建议改用专门的日志表(比如activity_log),或者ELK、Graylog这类专业日志系统;如果坚持用文件存储,可以按日期拆分日志(比如activity_20240520.jsonl),避免单个文件体积过大。

内容的提问来源于stack exchange,提问作者ERaufi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 08:25:31