Yii2中如何将API返回的JSON数据保存到数据库?
嘿,刚好我之前在Yii2里处理过类似的需求,给你一步步拆解怎么把API返回的JSON数据存到数据库:
步骤1:准备数据库表和ActiveRecord Model
首先你得有对应的数据表,假设我们要存的是设备的Ping记录,表结构可以这样设计(适配你返回的字段):
CREATE TABLE ping_records ( id INT AUTO_INCREMENT PRIMARY KEY, msn VARCHAR(20) NOT NULL COMMENT '设备编号', ping_datetime DATETIME NOT NULL COMMENT 'Ping时间', ping_value INT NOT NULL COMMENT 'Ping值', UNIQUE KEY idx_msn_ping_time (msn, ping_datetime) -- 可选,防止同一设备同一时间的重复记录 );
然后用Yii2的Gii工具生成对应的ActiveRecord Model(或者手动写),比如命名为PingRecord,生成后记得在Model里配置好字段映射和验证规则:
// app/models/PingRecord.php namespace app\models; use yii\db\ActiveRecord; class PingRecord extends ActiveRecord { public static function tableName() { return 'ping_records'; } public function rules() { return [ [['msn', 'ping_datetime', 'ping_value'], 'required'], [['ping_datetime'], 'safe'], [['ping_value'], 'integer'], [['msn'], 'string', 'max' => 20], [['msn', 'ping_datetime'], 'unique', 'targetAttribute' => ['msn', 'ping_datetime']], ]; } }
步骤2:解析API返回的JSON数据
不管你是用curl还是Yii2自带的yii\httpclient\Client调用API,拿到返回的JSON字符串后,先把它转成PHP数组(或者对象,看你习惯):
// 假设$apiResponse是API返回的原始JSON字符串 $dataArray = json_decode($apiResponse, true); // 转成关联数组 // 如果想转成对象数组,就用json_decode($apiResponse),后面取值用$item->MSN这种方式
步骤3:保存数据(两种方式)
根据数据量大小,选择合适的保存方式:
方式一:单条循环保存(数据量小的时候用)
这种方式会自动触发Model的验证规则,适合数据量不多的场景:
use app\models\PingRecord; use Yii; foreach ($dataArray as $item) { $model = new PingRecord(); // 赋值字段,注意和Model里的属性名对应 $model->msn = $item['MSN']; // 把ISO格式的时间转成数据库支持的DATETIME格式 $model->ping_datetime = date('Y-m-d H:i:s', strtotime($item['PingDateTime'])); $model->ping_value = $item['PingValue']; // 保存并处理失败情况 if (!$model->save()) { // 可以把错误日志记录下来,方便排查 Yii::error("保存Ping记录失败: " . print_r($model->errors, true)); } }
方式二:批量插入(数据量大的时候用)
如果API返回的数据很多,单条保存效率太低,用批量插入能大幅提升性能,不过要注意批量插入不会自动触发验证,所以最好先做验证:
use app\models\PingRecord; use Yii; use yii\db\Command; $validData = []; foreach ($dataArray as $item) { $model = new PingRecord(); $model->msn = $item['MSN']; $model->ping_datetime = date('Y-m-d H:i:s', strtotime($item['PingDateTime'])); $model->ping_value = $item['PingValue']; // 先验证数据合法性 if ($model->validate()) { $validData[] = $model->attributes; } else { Yii::error("Ping记录验证失败: " . print_r($model->errors, true)); } } // 批量插入合法数据 if (!empty($validData)) { Yii::$app->db->createCommand() ->batchInsert( PingRecord::tableName(), ['msn', 'ping_datetime', 'ping_value'], // 要插入的字段名 $validData // 待插入的数据数组 ) ->execute(); }
额外注意事项
- 时间格式处理:API返回的
2018-05-04T16:33:27是ISO8601格式,用strtotime可以直接转成时间戳,再格式化数据库需要的格式;如果担心时区问题,可以用DateTime类处理:$dateTime = new DateTime($item['PingDateTime']); $model->ping_datetime = $dateTime->format('Y-m-d H:i:s'); - 重复数据处理:如果API可能返回重复的记录,除了给表加唯一键,也可以在保存前先查询是否存在,避免重复插入;
- 异常捕获:如果调用API或者保存数据时可能出现网络问题、数据库连接问题,最好加上try-catch块捕获异常,避免程序崩溃。
内容的提问来源于stack exchange,提问作者Moeez




