XORM框架在Go项目中需按/internal/db、/model、/repo、/migration分层:db管理引擎与连接,model定义带xorm标签的导出结构体,repo封装CRUD,migration控制表结构演进。

要让XORM框架在Go项目中稳定支撑数据层、便于维护和扩展,必须从目录结构上隔离关注点,避免模型、引擎初始化、迁移逻辑混杂在main包里。
基础分层结构设计
采用标准内部模块化布局,将数据访问能力封装在/internal目录下,与业务逻辑解耦:
├── /internal
│ ├── /db ← XORM引擎管理、连接池配置、全局engine实例
│ ├── /model ← 所有结构体定义,含xorm标签,不依赖任何框架代码
│ ├── /migration ← 表结构同步逻辑(Sync2)、版本化迁移脚本(可选)
│ └── /repo ← 数据访问层(Repository),封装基于engine的CRUD操作
这种划分确保model层可被单元测试直接导入,db层可被不同服务复用,repo层为controller提供干净接口。
db目录:引擎初始化与连接管理
在/internal/db目录下创建engine.go:
第一步:声明全局engine变量,类型为*xorm.Engine,不导出;
第二步:编写Init函数,接收DSN字符串,调用xorm.NewEngine创建引擎;
第三步:设置连接池参数(SetMaxIdleConns/SetMaxOpenConns),并启用ShowSQL(仅开发环境);
第四步:执行engine.Ping()验证连通性,失败则panic或返回error;
第五步:将engine赋值给全局变量,供其他包通过GetEngine()获取。
【Init函数必须在main中最早调用,否则repo层使用时engine为nil】
model目录:结构体与数据库表严格映射
每个结构体文件名小写,对应单张表(如user.go → user表),结构体名大写(User)。
方法一:使用xorm标签精确控制字段行为
Id int64 `xorm:"pk autoincr"` → 主键+自增,不可省略pk,否则Sync2不会建主键索引
Name string `xorm:"varchar(64) notnull unique"` → 长度、非空、唯一约束全在标签里声明
CreatedAt time.Time `xorm:"created"` → 插入时自动写入当前时间,无需手动赋值
方法二:嵌入通用时间戳字段提升复用性
type BaseTime struct { CreatedAt time.Time `xorm:"created"` UpdatedAt time.Time `xorm:"updated"` }
type User struct { Id int64 `xorm:"pk autoincr"`; Username string `xorm:"varchar(64)"`; BaseTime }
注意:结构体字段必须是导出(首字母大写),否则xorm无法反射读写。
repo目录:面向业务的数据操作封装
每个repo文件对应一个model(如user_repo.go对应User结构体),不暴露xorm.Engine。
func NewUserRepo() *UserRepo { return &UserRepo{} }
type UserRepo struct{}
func (r *UserRepo) GetByID(id int64) (*model.User, error) {
user := new(model.User)
has, err := db.GetEngine().ID(id).Get(user)
if err != nil { return nil, err }
if !has { return nil, errors.New("user not found") }
return user, nil
}
这一步把engine.Get()细节收口,上层service只关心“查用户”,不关心用的是xorm还是原生SQL。
migration目录:表结构演进可控化
方法一:启动时强制同步(适合开发/测试)
在cmd/main.go中,db.Init()之后立即调用:
err := db.GetEngine().Sync2(new(model.User), new(model.Order))
if err != nil { log.Fatal(err) }
方法二:按需执行迁移(生产推荐)
新建/internal/migration/v1_init.go,定义Migration结构体,含Up/Down方法;
Up方法内调用engine.Sync2或手写SQL执行CREATE TABLE;
通过命令行参数(如--migrate=v1)触发指定版本迁移。
【Sync2会删除不存在于结构体中的列,生产环境禁用】











