tp8.0新增数据必须用save(),create()已移除;推荐db::insert()快速插入或save()配合allowfield()/validate()校验;注意字段蛇形转换与显式事务控制。

thinkphp8.0新增数据用save()还是create()?
TP8.0 已彻底移除 create() 方法,也不推荐直接 new 模型后赋值再 save()——除非你明确关闭了自动验证和过滤。默认情况下,必须走 save() + 数据预处理,否则容易因字段未通过验证而静默失败或报错 ValidateException。
常见错误现象:save() 返回 false 但没报错、数据库无记录、日志里出现 data not valid 提示。
- 推荐做法:用
Db::table('user')->insert($data)快速插入(绕过模型层,无验证) - 需校验/事件/自动完成时:用模型的
save(),但数据必须先经allowField()或validate(true)显式控制 - 批量插入请用
Db::table('user')->insertAll($list),别用模型循环save(),性能差且事务难控
使用Db::insert()时字段名不匹配怎么办?
TP8.0 的 Db::insert() 不做字段映射,传入键名必须与数据库列名完全一致(区分大小写,尤其在 Linux 环境下)。若用驼峰命名的数组(如 ['userName' => 'Tom']),会直接报错 SQLSTATE[HY000]: General error: 1364 Field 'user_name' doesn't have a default value。
解决方法:
- 手动转换键名:用
think\helper\Str::snake()处理字段,例如array_change_key_case(array_map([Str::class, 'snake'], $data)) - 在模型中定义
$convertName = true并配合setAttr实现自动映射(仅限模型操作) - 更稳妥的做法:插入前用
Db::getFields('user')获取真实字段列表,过滤掉非法键
模型save()新增失败却没提示具体原因?
默认 save() 抛出异常时只带基础信息,很难定位是验证失败、唯一索引冲突,还是 SQL 错误。比如插入重复邮箱,可能只报 save false,而不告诉你违反了 uk_email 约束。
调试建议:
- 开启数据库日志:
db.trace = true(配置文件),看最终执行的 SQL 和绑定参数 - 捕获
ValidateException单独处理,$e->getError()能拿到具体字段错误 - 对主键冲突类问题,改用
Db::insertGetId($data)并检查返回是否为 0(表示 insert 失败,可能是唯一键冲突)
TP8.0新增数据要不要手动开启事务?
单条新增不需要——TP8.0 的 Db::insert() 和模型 save() 默认已是原子操作。但只要涉及关联表写入(如用户+用户扩展表+日志表),就必须显式用 Db::transaction() 包裹,否则部分成功部分失败会导致数据不一致。
注意点:
-
Db::transaction()内不能混用不同连接(比如一个用Db::name('user'),另一个用Db::connect('slave')) - 模型操作在事务中仍要调用
$model->isUpdate(false)显式声明是新增,否则可能误判为更新 - 事务内抛异常会自动回滚,但不要依赖
try/catch吞掉所有异常——至少记录$e->getMessage(),否则线上排查极困难
userPhone,后端没转成 user_phone 就塞进 Db::insert(),结果字段被跳过、非空字段缺失、整条插入静默失败。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











