Iris 框架不内置软删除机制,因其定位轻量级 HTTP 层,不耦合 ORM;需在 Repository 层统一拦截查询与更新,用 deleted_at 字段标记状态,并封装 FindByID、Delete、Restore 等方法确保逻辑一致。

Iris 框架本身不内置软删除机制,必须手动实现;核心是拦截查询、更新逻辑,并统一用 deleted_at 字段标记状态。
为什么 Iris 没有现成的软删除支持
Iris 是轻量级 Web 框架,定位在路由、中间件、视图渲染等 HTTP 层,不耦合 ORM 或模型层逻辑。它不提供类似 GORM 的 SoftDelete 插件或自动 WHERE deleted_at IS NULL 过滤。所有数据操作最终依赖你选用的数据库驱动(如 database/sql + pgx / mysql)或第三方 ORM(如 GORM、ent)。
这意味着:软删除不是 Iris 的功能,而是你模型设计 + 查询封装的责任。
在 MVC 结构中统一拦截查询(推荐用 Repository 模式)
不要在每个 Controller 里重复写 WHERE deleted_at IS NULL —— 容易遗漏、难维护。正确做法是在 Repository 层封装基础查询逻辑:
- 定义统一的软删除字段,例如
deleted_at *time.Time(注意指针类型,便于判空) - 所有 Repository 的
FindOne、FindAll方法默认加AND deleted_at IS NULL - 提供显式方法如
FindWithDeleted()或ForceDelete()处理特殊场景 - 避免在 Controller 直接调用
db.Query,全部走 Repository 接口
示例(使用 database/sql):
// user_repo.go
func (r *UserRepository) FindByID(id int) (*User, error) {
var u User
err := r.db.QueryRow("SELECT id, name, deleted_at FROM users WHERE id = $1 AND deleted_at IS NULL", id).Scan(&u.ID, &u.Name, &u.DeletedAt)
if errors.Is(err, sql.ErrNoRows) {
return nil, nil // or custom ErrNotFound
}
return &u, err
}
更新和删除操作必须原子化处理
软删除本质是 UPDATE,不是 DELETE。常见错误是直接调用 DELETE FROM users —— 这会绕过软删逻辑,数据真丢了。
- Controller 中调用的应是
userRepo.Delete(id),而非db.Exec("DELETE ...") -
Delete()方法内部执行:UPDATE users SET deleted_at = NOW() WHERE id = ? AND deleted_at IS NULL - 返回影响行数,若为 0,说明记录已软删或不存在,可据此返回 404
- 恢复操作(undo delete)就是
UPDATE ... SET deleted_at = NULL,需额外提供Restore()
关键点:AND deleted_at IS NULL 条件防止重复软删或误恢复。
注意 GORM 用户的陷阱:Iris 不接管 GORM 钩子
如果你用 GORM 作为 ORM,它支持 gorm.Model(&u).Unscoped().Delete() 绕过软删,但 Iris 对此完全无感知。问题常出在:
- 忘记在 GORM 初始化时启用软删除:
db.SetupJoinTable(...)不相关,重点是gorm.DefaultSchemaName和全局TableName设置是否一致 - 在 Controller 里混用原生 SQL 和 GORM,导致部分接口漏掉
Unscoped()或多加了Unscoped() - GORM 的
Count()默认也过滤软删数据,但统计“总用户数”时你可能需要Unscoped().Count()—— 这类业务语义必须显式区分,不能依赖框架自动推断
最稳妥的方式:把 GORM 实例封装进 Repository,所有对外暴露的方法都明确语义,比如 CountActiveUsers() vs CountAllUsers()。
软删除真正的复杂点不在代码怎么写,而在于业务边界是否清晰:哪些列表页要含已删数据?导出报表是否包含?搜索是否默认排除?这些决定必须前置到需求阶段,而不是在 WHERE 条件里临时加 or 删一个 IS NULL。


















