Iris本身不提供依赖注入,需借助dig等第三方容器或手写单例管理;Repository接口应通过构造函数注入,避免硬编码初始化,确保DB上下文、事务可控及可测试性。

怎么在Iris里注入和使用Repository接口
直接把 IRolePermissionRepository 这类接口塞进 handler 或 service 的构造函数里,Iris 本身不处理依赖注入——得靠 Go 生态惯用的第三方容器(比如 github.com/uber-go/dig)或手写单例管理。Iris 只管 HTTP 生命周期,Repository 层必须自己搭好生命周期桥梁。
常见错误是:在 handler 里 new 一个 &rolePermissionRepository{} 就开用,结果数据库上下文没传进去、事务无法控制、测试时无法 mock。正确做法是把 Repository 实例作为依赖传入,而不是在业务逻辑里硬编码初始化。
- 定义接口时方法签名要明确是否需要
context.Context参数(尤其涉及超时或取消) - 实现类里不要持有全局 DB 句柄,应通过构造函数接收
*sql.DB或 ORM 的*gorm.DB - 如果用了
dig,注册时记得用dig.As(new(IRolePermissionRepository))做类型映射,否则 resolve 会失败
空结构体实现Repository接口为什么可行
Go 里用 &entraceRepository{} 这种空结构体实现接口,不是为了省内存,而是为了零字段、无状态、可安全共享。它不存任何运行时数据,所有方法都只依赖传入参数和外部依赖(比如 DB),天然适合做无状态仓储层入口。
但容易踩的坑是:误以为“空结构体 = 可以随便 new 多次”,其实如果它的方法里用了闭包捕获变量、或内部缓存了连接池句柄,那就不再是无状态了。一旦混入状态,多 goroutine 并发调用就会出问题。
- 确认所有方法都不读写结构体字段(
func (r *entraceRepository) Get(...) { ... }中没用到r.xxx) - 避免在空结构体方法里初始化全局变量或复用未加锁的 map/slice
- 单元测试时可以直接 new 接口实现,不用启动整个 DI 容器,这是空结构体的真实价值
AutoMapper 类似功能在 Iris 生态怎么替代
Iris 本身没有 AutoMapper,.NET 那套自动属性映射在 Go 里既不必要也不推荐。Go 更倾向显式转换,用工具生成(比如 github.com/mitchellh/mapstructure 或 golang.org/x/exp/maps)或者手写 ToDTO() 方法。
强推自动映射反而容易掩盖字段变更风险:比如数据库加了个新列,AutoMapper 默认忽略它,但业务可能正需要这个字段做判断——静默跳过比报错更危险。
- DTO 结构体字段名和 Entity 字段名保持一致,能省掉 80% 的手动赋值
- 用
mapstructure.Decode()处理 map → struct 场景(如从 query param 或 JSON body 构建 filter) - 如果真要批量映射,优先选 compile-time 代码生成工具(如
entc配合模板),而非 runtime 反射方案
Repository 方法要不要返回 error
要。所有涉及 DB 查询、写入、事务的方法,必须返回 error。Iris 的 handler 签名是 func(ctx iris.Context),你没法在中间件统一 recover 数据库 panic——Go 不鼓励用 panic 做业务错误处理。
典型反模式:func (r *repo) GetByID(id int) User { row := r.db.QueryRow(...); row.Scan(...); return user } ——这里 Scan 失败就 panic,HTTP 请求直接 500,连日志都难定位。
- 标准写法是
func (r *repo) GetByID(id int) (User, error),caller 决定是重试、降级还是透传错误 - 错误值建议包装成自定义 error(如
ErrUserNotFound),方便 handler 统一转成 404 - 别用
fmt.Errorf("get user %d failed: %w", id, err)包裹底层 error 后直接返回,会丢失原始错误类型判断能力
实际项目里最常被忽略的,是 Repository 方法的**可观测性埋点**:比如没在关键查询前后打日志或记录耗时 metric。空结构体 + 接口抽象解决了组织问题,但没解决诊断问题——DB 慢了,你得知道是哪个 Repository 的哪个方法拖慢了整条链路。











