codeigniter防重复插入需分场景应对:一、前端禁用按钮+后端token校验;二、数据库唯一约束+异常捕获;三、高并发时用表锁或select...for update;四、批量导入用on duplicate key update。

CodeIgniter 表单提交时防止重复插入,关键在于区分“用户误操作导致的重复提交”和“并发请求引发的竞态条件”,两者需用不同策略应对。单纯前端禁用按钮只能防手抖,后端必须有兜底机制。
一、基础防护:前端按钮禁用 + 后端 Token 校验
这是最常用且成本最低的组合方案,适合注册、留言、普通表单等场景。
- 用户访问表单页时,控制器生成唯一 Token(如 UUID),存入 Session 或 Redis(建议设 5–10 分钟过期)
- 将 Token 嵌入表单隐藏域:
<input type="hidden" name="token" value="<?= $token ?>"> - 提交时验证 Token 是否存在且未使用过;验证通过则处理业务并立即删除该 Token
- 验证失败(空、无效、已用)直接返回错误,不执行数据库写入
二、强一致性保障:数据库唯一约束 + 异常捕获
这是最可靠的一层防线,尤其适用于邮箱、手机号、订单号等天然具备唯一性的字段。
- 在数据库对应字段上添加 UNIQUE INDEX(如
ALTER TABLE users ADD UNIQUE(email)) - 后端插入时用 try-catch 捕获数据库异常(CI3 用
$this->db->error(),CI4 用$e->getCode() === '23000') - 若捕获到唯一键冲突错误(MySQL 错误码 1062),返回友好提示:“该邮箱已被注册”,而非服务器错误
- 注意:此法依赖数据库结构变更,但它是防重最根本、最不可绕过的手段
三、高并发场景:表锁或行锁确保检查与插入原子性
当无法加唯一索引(如老旧系统、权限受限),又面临大量并发注册时,需靠锁机制串行化关键操作。
- 在模型中使用
$this->db->query('LOCK TABLES users WRITE')获取写锁(CI3) - 紧接着查邮箱是否存在,再决定是否插入;全部操作完成后执行
UNLOCK TABLES - CI4 中更推荐用事务 +
SELECT ... FOR UPDATE锁定特定行(如WHERE email = ?),粒度更小、性能更好 - 锁操作必须包裹在 try/finally 中,避免因异常导致锁未释放而阻塞后续请求
四、批量导入去重:ON DUPLICATE KEY UPDATE
适用于 Excel 导入、后台批量新增等含多条记录的场景,避免逐条判断效率低、易出错。
- 确保目标表有主键或唯一索引(如
email字段) - 不用
insert_batch(),改用原生 SQL 配合 CI 查询构建器: INSERT INTO users (email, name, created_at) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE name = VALUES(name), updated_at = NOW()- 若只想跳过重复项不更新,可写
ON DUPLICATE KEY UPDATE id = id(id 为主键)











