MySQL的insert_id()可靠但多语句时可能出错,PostgreSQL需手动RETURNING,SQLite需开启外键和避免嵌套事务,SQL Server需N'前缀防乱码,Oracle依赖序列且不支持limit,各驱动错误处理差异大。

MySQL 和 PostgreSQL 的 last_insert_id() 行为不一致
CodeIgniter 的 insert_id() 方法在不同驱动下返回逻辑不同,不是所有数据库都支持“自动获取刚插入的 ID”——MySQL 用 LAST_INSERT_ID(),PostgreSQL 必须显式调用 RETURNING id 或查 pg_last_oid(),但 CI 3.x 默认不启用 RETURNING。
实操建议:
- PostgreSQL 场景下,必须在
INSERT语句末尾手动加RETURNING id,并用$this->db->query()->row()取值,别依赖insert_id() - MySQL 驱动下
insert_id()可靠,但若执行了多条语句(如触发器里又插了一条),可能返回非预期 ID - CI 4 已改用原生
lastInsertId(),但需确认 PDO 连接配置中ATTR_EMULATE_PREPARES为false,否则 PostgreSQL 下会返回 0
SQLite 驱动不支持事务嵌套和外键约束默认关闭
CI 自带的 SQLite 驱动(PDO_sqlite)在开启事务时不会报错,但实际不生效;且外键检查默认禁用,FOREIGN KEY 约束形同虚设。
实操建议:
- 连接后立即执行
$this->db->query('PRAGMA foreign_keys = ON'),否则关联删除/更新不会触发约束 - 避免在 SQLite 中使用
$this->db->trans_start()嵌套,它只模拟事务,底层不支持 SAVEPOINT;单层事务也建议用beginTransaction()+commit()显式控制 - 迁移脚本里写
CREATE TABLE时,别省略WITHOUT ROWID或STRICT模式声明——CI 不校验语法,但 SQLite 3.37+ 会静默忽略非法定义
escape_str() 在 SQL Server 驱动中对 Unicode 字符处理异常
SQL Server 驱动(sqlsrv)的 escape_str() 方法未正确前缀 N',导致中文、emoji 等被截断或乱码,尤其在 LIKE 查询或参数绑定失败回退到拼接时暴露问题。
实操建议:
- 永远优先用查询绑定:
$this->db->like('name', $keyword)而非"name LIKE '%" . $this->db->escape_str($keyword) . "%'" - 若必须拼接,对 Unicode 字符串手动加
N前缀:"N'" . $this->db->escape_str($str) . "'" - 检查
sqlsrv驱动配置中'ConnectionOptions' => ['Database' => 'xxx']是否含'CharacterSet' => 'UTF-8'——CI 3.x 不自动设置,缺了就丢字
Oracle 驱动要求序列名与表名强绑定,且不兼容自增列语法
Oracle 没有 AUTO_INCREMENT,CI 的 insert_id() 在 Oracle 驱动下直接返回 0;它依赖序列(SEQUENCE)和触发器,但 CI 不自动生成或管理这些对象。
实操建议:
- 建表后必须手动生成对应序列,命名规则通常是
{table}_SEQ,CI 的insert_id()才会尝试查这个序列 - 插入前得先查序列:
$id = $this->db->query("SELECT {table}_SEQ.NEXTVAL FROM DUAL")->row()->NEXTVAL,再带入 INSERT - Oracle 驱动不支持
limit(),分页必须用ROWNUM嵌套子查询,CI 的limit(10,20)在 Oracle 下静默失效
跨平台最麻烦的从来不是语法差异,而是各驱动对“失败”的沉默程度——MySQL 报错,SQLite 吞错,Oracle 假成功。别信 insert_id() 返回非零就等于插入成功。











