PHP写入JSON文件时数据丢失且从头重复的原因及解决
JSON文件追加数据丢失的原因及解决办法
问题原因
你的脚本出现数据丢失的核心原因是并发写入冲突。当多个请求同时访问这个脚本时,会出现以下时序问题:
- 请求A读取
api.json的旧数据 - 请求B同时也读取到了同一版旧数据
- 请求A把新数据追加后写入文件
- 请求B基于之前读的旧数据追加新数据,然后写入文件,直接覆盖了请求A的修改结果
这种情况下,最后完成写入的请求会覆盖之前所有的新增数据,导致中间的数据丢失。
另外你的代码里还有一个小语法问题:数组里的'talktime' : '2023-09-08 00:00:10'用了冒号,PHP数组键值对应该用=>,不过这个不是导致数据丢失的直接原因,但建议修正。
解决方案
方案1:添加文件锁机制
通过文件锁确保同一时间只有一个进程能读写JSON文件,避免并发冲突。修改后的代码如下:
$filePath = 'data/api.json'; // 以读写模式打开文件,文件不存在则创建 $fileHandle = fopen($filePath, 'c+'); if ($fileHandle) { // 获取独占锁,阻塞直到获取到锁 if (flock($fileHandle, LOCK_EX)) { // 读取文件内容 $currentContent = stream_get_contents($fileHandle); // 处理文件为空或JSON解析失败的情况,默认返回空数组 $dataArray = json_decode($currentContent, true) ?: []; $newRecord = [ 'id' => $_GET['id'], 'name' => 'SIMONE', 'talktime' => date('Y-m-d H:i:s') // 建议用当前时间,而非固定值 ]; $dataArray[] = $newRecord; $finalContent = json_encode($dataArray, JSON_PRETTY_PRINT); // 将文件指针移到开头,截断原有内容,写入新数据 ftruncate($fileHandle, 0); rewind($fileHandle); fwrite($fileHandle, $finalContent); // 释放锁 flock($fileHandle, LOCK_UN); $message = "<label class='text-success'>File Appended Successfully</label>"; } else { $message = "<label class='text-danger'>Failed to acquire file lock</label>"; } fclose($fileHandle); } else { $message = "<label class='text-danger'>Failed to open target file</label>"; }
关键说明:
- 使用
flock($handle, LOCK_EX)获取独占锁,确保同一时间只有一个进程能操作文件 - 处理文件为空的情况,避免
json_decode返回null导致后续数组追加报错 - 用
ftruncate和rewind组合覆盖原有文件内容,替代直接file_put_contents
方案2:改用数据库存储
如果你的应用并发量较高或者数据量持续增长,建议放弃用JSON文件存储数据,改用MySQL、SQLite等数据库。数据库本身具备事务、行锁等机制,能更可靠地处理并发写入场景,同时方便后续的数据查询、统计等操作。
内容的提问来源于stack exchange,提问作者Bajiroot Baji
相关产品推荐
相关产品推荐

