CodeIgniter自定义类调用insert()必须先获取CI实例并加载数据库类,否则报“Call to a member function insert() on null”;CI2/3需用get_instance(),CI4必须通过service('database')或Database::connect()获取DB实例。

CodeIgniter 2.x 中自定义类调用 insert() 的正确姿势
必须先获取 CI 实例并加载数据库类,否则直接调用 $this->db->insert() 会报 Fatal error: Call to a member function insert() on null。自定义类不自动继承控制器上下文,$this->db 不是现成的。
实操建议:
- 在自定义类构造函数中用
get_instance()获取 CI 引用:$this->ci =& get_instance();
- 手动加载数据库(如果尚未加载):
$this->ci->load->database();
- 再执行插入:
$this->ci->db->insert('users', array('name' => 'Alice', 'email' => 'a@b.com')); - 检查是否成功:
if ($this->ci->db->affected_rows() === 1) { /* 成功 */ },注意不要用insert_id()判断成败,它在失败时也可能返回 0
CodeIgniter 3.x/4.x 自定义类里复用 DB 连接的关键区别
CI3 开始支持依赖注入,但自定义类仍需显式访问 CI 实例;CI4 彻底转向服务定位器模式,$this->db 不能直接用,必须通过 service('database') 获取。
常见错误现象:在 CI4 自定义类中写 $this->db->table('x')->insert([...]),报 Call to a member function table() on null。
实操建议:
- CI3:继续用
get_instance(),但推荐改用CI =& get_instance()避免引用混淆 - CI4:必须用服务容器:
$db = \Config\Database::connect(); // 或 service('database') - CI4 插入写法:
$db->table('users')->insert(['name' => 'Bob', 'email' => 'b@c.com']); - CI4 不再有全局
$this->db,所有 DB 操作必须基于具体连接实例
insert() 执行失败却不报错?排查这三处硬伤
最常被忽略的是字段名与数据库实际列名不一致、NULL 值写入非空字段、以及未开启查询日志导致 silent fail。
实操建议:
- 确认表字段存在且大小写匹配(MySQL 默认不区分,但某些配置或引擎下会敏感)
- 检查字段是否设为
NOT NULL却传了null或空字符串 —— CodeIgniter 不做字段级校验,直接交由 MySQL 拒绝 - 临时开启数据库调试:
$this->ci->db->save_queries = TRUE;
,之后用$this->ci->db->queries查看最后执行的 SQL 是否符合预期 - 对 CI4,用
$db->getLastQuery()->getQuery()获取原始 SQL
批量插入用 insert_batch() 时的性能与事务陷阱
单次插入 100 条用 insert_batch() 比循环调用 insert() 快 5–8 倍,但默认不开启事务,中途出错会导致部分写入。
实操建议:
- 务必手动包裹事务:
$this->ci->db->trans_start();<br>$this->ci->db->insert_batch('logs', $data);<br>$this->ci->db->trans_complete(); - CI4 对应写法:
$db->transStart();<br>$db->table('logs')->insertBatch($data);<br>$db->transComplete(); - 注意
insert_batch()的$data必须是索引数组,每个子数组键名必须严格对应字段名,多一个少一个都会导致 SQL 错误 - 单条数据超 1MB 或批量超 1000 行时,考虑分片,避免 MySQL packet size 限制触发
MySQL server has gone away
真正麻烦的不是写不对 insert,而是以为写对了——字段名拼错、NULL 写进 NOT NULL 字段、没开事务却以为原子性已保障,这些都不会抛异常,只默默丢掉数据。

















