在iris mvc中应通过app.registerdependency(*gorm.db)注册gorm单例,于database/database.go中初始化并配置连接池(setmaxopenconns/setmaxidleconns),controller构造函数注入使用;分页需校验参数并复用scope与count逻辑;model须显式标注主键、时间戳、软删及外键;事务须用db.transaction()函数式封装,全程使用tx且避免io操作。

怎么在Iris MVC结构里初始化GORM并全局可用
不能把gorm.DB实例塞进每个controller里传,得做成单例+依赖注入式复用。Iris本身不提供DI容器,但你可以用包级变量或app.RegisterDependency注册它——后者更可控、可测试。
常见错误是每次请求都新建gorm.Open,导致连接泄漏或panic;或者没调sqlDB.SetMaxOpenConns,数据库扛不住并发。
- 在
database/database.go里定义var DB *gorm.DB,init()函数中完成DSN解析、Open、连接池配置 - 调用
DB.DB().SetMaxOpenConns(100)和SetMaxIdleConns(20),避免连接耗尽 - 别在handler里用
defer DB.Close()——那是全局实例,关了整个服务就断库了 - 如果要用
app.RegisterDependency,注册类型为*gorm.DB,controller构造函数参数声明它即可
Controller里怎么安全地用GORM查数据(含分页)
Iris的controller不是自动绑定GORM的,你得手动把*gorm.DB传进去,或从上下文取(推荐前者)。重点不是“能不能查”,而是“查错时怎么不崩、不暴露敏感信息”。
典型翻车点:用c.URLParamInt("page")没检查error就直接算offset,结果page=abc导致panic;或者Limit/Offset顺序写反,MySQL报错。
- 必须校验
page和size:用c.URLParamIntDefault("page", 1)和c.URLParamIntDefault("size", 20),再加范围限制(如size > 100就强制设为100) - GORM分页固定写法:
db.Scopes(paginate(page, size)).Find(&users),其中paginate是自定义Scope函数,内部做.Offset((page-1)*size).Limit(size) - 查总数必须另起一次
Count(&total),且条件要和主查询完全一致(建议抽成func(db *gorm.DB) *gorm.DB复用where逻辑) - 别用
db.Raw()拼接用户输入,哪怕已转int——统一走GORM链式API或Where("status = ?", status)参数化
Model定义要注意哪些GORM兼容细节
Iris不干涉model层,但GORM对struct tag很敏感。一个字段少写gorm:"primaryKey",First()就可能查不到;时间字段没配autoCreateTime,CreatedAt永远是零值。
最容易被忽略的是软删除和唯一索引——GORM默认开启gorm.DeletedAt软删,但如果你的表没这个字段,所有Delete()操作都会静默失败。
-
ID uint字段必须显式加gorm:"primaryKey",否则GORM认不出主键 - 时间字段用
time.Time类型,搭配gorm:"autoCreateTime;autoUpdateTime",别自己赋值 - 唯一约束写成
gorm:"uniqueIndex",不是unique(后者是SQL-level,GORM不识别) - 外键关联字段要同时定义“ID字段”和“结构体字段”,比如
UserID uint+User User,并用gorm:"foreignKey:UserID"标明关系
事务怎么在Iris handler里正确开启和回滚
别在controller里直接调db.Transaction()然后嵌套一堆逻辑——出错时recover不到,事务不会自动回滚。Iris没有类似Spring的@Transactional注解,得靠显式控制流。
最稳妥的方式是把事务逻辑封装成函数,handler只负责传参和错误转发。否则一个return漏写,事务就卡住,连接池慢慢被占满。
- 用
db.Transaction(func(tx *gorm.DB) error { ... })包裹全部DB操作,返回error触发自动回滚 - 事务内不要用
db,一律用tx,否则会跳出事务上下文 - 如果需要跨多个model操作,把
tx作为参数传给各service函数,而不是在service里重新GetDB() - 别在事务里做HTTP调用或文件IO——超时或失败会导致事务长时间悬挂
db.Exec("SELECT 1")验证连通性,再跑一遍AutoMigrate确保字段变更已生效——这些步骤不写进启动流程,半夜报警全是“connection refused”或“column not found”。











