codeigniter通过trans_start()和trans_complete()实现多表插入的原子性保障,自动检测错误并回滚;必须配合trans_status()判断结果,且高并发下需结合unique索引或select ... for update确保数据一致性。

CodeIgniter(CI)本身不内置完整的事务管理封装,但支持原生数据库事务控制。多表同时插入必须依赖事务来保障原子性——要么全部成功,要么全部回滚,避免数据不一致。
启用并手动控制事务
CI 的 $this->db->trans_start() 和 $this->db->trans_complete() 是最常用、最稳妥的方式。它会自动检测执行过程中的错误,并在出错时回滚所有已执行语句。
- 调用 trans_start() 后,后续所有数据库操作(包括多张表的 insert、update、delete)都会被纳入当前事务
- 必须紧接着调用 trans_complete() 才会真正触发提交或回滚逻辑
- 若中间某条 SQL 报错(如唯一键冲突、字段超长、外键失败),trans_complete() 会自动执行回滚
多表插入的典型写法
以下是一个用户注册时需同时写入 users 和 profiles 表的示例:
$this->db->trans_start();
$this->db->insert('users', ['email' => $email, 'password' => $hash]);
$user_id = $this->db->insert_id();
$this->db->insert('profiles', ['user_id' => $user_id, 'nickname' => $nick]);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE) {
// 任一插入失败,整个事务已回滚
return false;
}
return true;
注意隔离级别与并发安全
CI 默认使用数据库默认隔离级别(如 MySQL InnoDB 的 REPEATABLE READ)。但在高并发注册场景下,仅靠事务不能防止邮箱重复——因为两个请求可能同时通过“查无此邮箱 → 插入”流程。
- 最可靠方案:给
users.email字段加 UNIQUE 索引,让数据库层拦截重复 - 若无法改表结构,可在事务内配合 SELECT ... FOR UPDATE 加行锁(需 InnoDB),例如:
$this->db->query("SELECT 1 FROM users WHERE email = ? FOR UPDATE", [$email]); - 避免在事务中做耗时操作(如 HTTP 请求、文件读写),否则会延长锁持有时间,影响并发性能
替代方案:显式 commit/rollback(高级控制)
当需要更精细判断或嵌套逻辑时,可关闭自动管理模式,改用:
- $this->db->trans_begin() —— 显式开启事务
- $this->db->trans_commit() 或 $this->db->trans_rollback() —— 手动决定结果
- 适合需要根据业务条件分支处理的场景,比如部分失败时记录日志再回滚











