iris 不提供内置软删除机制,因其职责限于请求路由与响应处理,软删除逻辑须由所选 orm(如 gorm)在数据层实现,包括 deletedat 字段定义、自动过滤及 unscoped 物理删除控制。

软删除必须手动实现,Iris 本身不提供内置软删除机制。它只是 HTTP 框架,数据库操作依赖你选用的 ORM 或原生 SQL 驱动(如 gorm、sqlx、ent 等),软删除逻辑需在数据层完成,Iris 负责把请求路由到对应处理函数并返回结果。
为什么 Iris 不处理软删除
Iris 的职责边界清晰:解析请求、中间件调度、响应渲染。它不介入数据模型定义或持久化逻辑。即使你用 gorm.Model 嵌套在 Iris handler 中,真正执行 DeletedAt 字段判断和 WHERE deleted_at IS NULL 过滤的是 GORM,不是 Iris。
- 试图在 Iris 的
Context或Application层“拦截 DELETE 请求并自动转为 UPDATE”会破坏分层原则,且无法适配不同 ORM 的软删字段名(is_deleted、status、deleted_at) - 所有“Iris 软删除插件”类方案,本质都是对底层 ORM 的封装,而非 Iris 自身能力
典型实现:GORM + Iris 结合方式
假设你使用 gorm 作为数据库层,且已按规范定义 DeletedAt 字段:
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"not null"`
DeletedAt time.Time `gorm:"index"`
}
在 Iris handler 中正确调用:
- 查询时自动过滤:确保初始化 GORM 时启用软删除(
gorm.WithContext(ctx).Where("deleted_at IS NULL")不是必须的,GORM 默认开启全局软删支持) - 执行软删:
db.Delete(&user)或db.Unscoped().Delete(&user)(后者物理删除) - 硬删需显式调用
Unscoped(),否则Delete默认是软删
示例 handler:
app.Delete("/users/{id}", func(ctx iris.Context) {
id, _ := ctx.Params().GetInt64("id")
var user User
if err := db.First(&user, id).Error; err != nil {
ctx.StatusCode(404)
ctx.JSON(iris.Map{"error": "not found"})
return
}
// 软删除触发 GORM 的 DeletedAt 自动填充
if err := db.Delete(&user).Error; err != nil {
ctx.StatusCode(500)
ctx.JSON(iris.Map{"error": err.Error()})
return
}
ctx.JSON(iris.Map{"message": "soft deleted"})
})
容易踩的坑
软删除不是加个字段就完事,常见疏漏点:
-
SELECT COUNT(*)类聚合查询默认包含已软删记录,需手动加WHERE deleted_at IS NULL条件,GORM 的Count方法也受软删影响,但需确认是否启用了Query模式 - 关联查询(如
Preload)中,被预加载的子表若也有软删字段,GORM 默认不会自动过滤它们,需显式配置Preload("Orders", func(db *gorm.DB) *gorm.DB { return db.Where("deleted_at IS NULL") }) - RESTful 设计中,
GET /users返回列表应默认排除软删项,但GET /users/{id}查单条时,若业务需要查“已删除但可恢复”的记录,则要加Unscoped()—— 这个逻辑必须由 handler 显式控制,不能交给 Iris 自动推断 - 前端传参若带
include_deleted=true,后端 handler 必须主动判断并切换 GORM scope,Iris 不会解析这个语义
软删除的核心约束始终在数据模型和 ORM 层,Iris 只是管道。最容易被忽略的是跨表关联时的软删穿透问题——子表记录是否随父表软删而隐式不可见,这完全取决于你写的 JOIN 条件和 Preload 配置,跟 Iris 没有半点关系。











