save()成功后直接读$model->attributes['id']即可获取自增主键id,前提是主键名为id(或primarykey()返回的字段)、数据库设自增、模型正确实例化且未手动修改isnewrecord状态。

save() 成功后直接读 $model->attributes['id'] 就行
只要不是批量插入,用 save() 新增一条记录后,主键 ID 会自动填充到模型属性里。前提是表主键字段名确实是 id(或你模型里 primaryKey() 返回的字段名),且数据库设了自增。
常见错误现象:$model->id 是 null 或 0,但其实数据已写入;这是因为没触发属性同步,应统一走 $model->attributes['id'],而不是直接访问 $model->id —— 后者在某些版本中可能未及时更新。
- 必须确保模型已通过
new User()实例化,且未手动设$model->id = 0或调用setIsNewRecord(false) - 如果主键字段名不是
id(比如叫user_id),要换成对应键名:$model->attributes['user_id'] - 若使用
asArray()查询或赋值,attributes不可用,此时只能走底层方式
createCommand()->insert() 后必须调 Yii::$app->db->getLastInsertID()
绕过模型、直连 DB 插入时,save() 的自动同步机制失效,ID 只能靠驱动返回。注意:这个方法只返回**最近一次 INSERT 操作**生成的 ID,不能跨连接、不能跨事务安全使用。
典型误用场景:在一个事务里执行多次 insert(),中间夹着查询或其它语句,再调 getLastInsertID() —— 结果可能错乱。
- 必须紧接在
execute()之后立刻调用,中间不能有其他写操作 - 如果用的是 MySQL,且插入的是多行(
batchInsert),getLastInsertID()返回的是第一行的 ID,不是最大 ID - PostgreSQL 不支持
getLastInsertID(),得改用RETURNING子句,例如:INSERT INTO user (name) VALUES ('a') RETURNING id
循环插入时,每次都要重置 setIsNewRecord(true)
很多人把 $model = new User() 写在循环外,导致反复调 save() 时,第二次起被当成更新操作(UPDATE),ID 读不到,甚至报主键冲突。
根本原因:Active Record 内部靠 isNewRecord 属性判断是 insert 还是 update;循环中不重置,它就一直认为是“已存在记录”。
- 正确写法是:循环体内每次都
new User(),或复用对象时显式调$model->setIsNewRecord(true) - 别依赖
$model->id = 0来“清空”,这不保证isNewRecord状态重置 - 如果循环内还做了
findOne()或load(),更要检查isNewRecord是否被意外覆盖
getErrors() 查不到 ID 时先确认是否真插入成功
拿到 null 或 0 的 ID,第一反应不该是查 ID 获取方式,而是确认插入本身有没有失败。因为 save() 失败时不会抛异常,只会静默返回 false,而 attributes['id'] 保持初始值。
最容易被忽略的点:模型规则把整型字段(如 tinyint)声明为 string 类型校验,传入 30 就会校验失败,save() 返回 false,但开发者常以为“没报错就是成功了”。
- 务必检查
$model->save()的返回值:if (!$model->save()) { var_dump($model->getErrors()); } -
getErrors()返回的是二维数组,格式类似['age' => ['This value must be a string.'],不是字符串 - 用 Gii 生成模型后,记得扫一眼
rules()里字段类型定义是否和数据库一致











