【golang】ORM框架操作数据库
文章目录
- 1. beego-orm
- 1.1 介绍
- 1.2 特性
- 1.3 使用
- 1.3.1 安装
- 1.3.2 导入与初始化
- 1.3.3 模型定义
- 1.3.3.1 定义模型代码
- 1.3.3.2 模型常用标签
- 1.3.4 基本操作(CURD)
- 1.3.4.1 创建orm实例
- 1.3.4.2 插入数据
- 1.3.4.3 查询数据
- 1.3.4.4 更新数据
- 1.3.4.5 删除数据
- 1.3.5 高级查询(QueryTable)
- 1.3.6 关联关系
- 1.3.6.1 一对一
- 1.3.6.2 一对多
- 1.3.6.3 多对多
- 1.3.6.4 关联操作
- 1.3.7 事务处理(Begin&Rollback&Commit)
- 1.3.8 支持原生sql(Raw)
- 1.3.9 表结构同步
- 1.3.10 连接池配置
- 1.3.11 性能优化
- 1.3.12 调试
- 1.3.13 常见问题
- 1.3.13.1 表名冲突
- 1.3.13.2 字段映射问题
- 1.3.13.3 时区问题
1. beego-orm
1.1 介绍
Beego ORM是Beego框架的官方对象关系映射组件,提供了一种面向对象的方式来操作数据库
1.2 特性
- 支持多种数据库:MySQL、PostgreSQL、SQLite、Oracle、MSSQL
- 自动表结构生成(Syncdb)
- 链式查询构建器(QuerySeter)
- 关联关系(一对一、一对多、多对多)
- 事务支持
- 连接池管理
- 原生SQL支持
1.3 使用
1.3.1 安装
go get github.com/beego/beego/v2
1.3.2 导入与初始化
import ("github.com/beego/beego/v2/adapter/orm"_ "github.com/go-sql-driver/mysql" // 导入对应数据库驱动,例如mysql
)func init() {// 注册驱动(可选)orm.RegisterDriver("mysql", orm.DRMySQL)// 注册默认数据库orm.RegisterDataBase("default", "mysql", "user:password@tcp(127.0.0.1:3306)/db_name?charset=utf8")// 注册模型orm.RegisterModel(new(User))
}
1.3.3 模型定义
1.3.3.1 定义模型代码
type User struct {Id int `orm:"auto;pk"`Username string `orm:"size(100);unique"`Password string `orm:"size(100)"`Age int `orm:"default(18)"`Created time.Time `orm:"auto_now_add;type(datetime)"`Updated time.Time `orm:"auto_now;type(datetime)"`
}// 自定义表名
func (u *User) TableName() string {return "users"
}
1.3.3.2 模型常用标签
标签 | 描述 | 示例 |
---|---|---|
auto | 自增字段 | orm:"auto" |
pk | 主键 | orm:"pk" |
size | 字段大小 | orm:"size(100)" |
default | 默认值 | orm:"default(0)" |
null | 允许NULL | orm:"null" |
index | 创建索引 | orm:"index" |
unique | 唯一约束 | orm:"unique" |
auto_now | 更新时间 | orm:"auto_now" |
auto_now_add | 创建时间 | orm:"auto_now_add" |
type | 字段类型 | orm:"type(text)" |
1.3.4 基本操作(CURD)
1.3.4.1 创建orm实例
o := orm.NewOrm()
1.3.4.2 插入数据
user := User{Username: "xujie",Password: "111111",Age: 29,
}// 插入数据语句
id, err := o.Insert(&user)
if err != nil {logs.Error("插入数据失败!!!")return
}
1.3.4.3 查询数据
// 通过主键查询
user := User{Id: 1}
_ := o.Read(&user)// 通过指定字段查询
user := User{Username: "test"}
_ := o.Read(&user, "Username")// 通过Filter方法查询多个
var users []*User// 在user表中查询年龄大于20岁的用户
num, err := o.QueryTable("user").Filter("age__gt", 20).All(&users)
if err != nil {logs.Error("查询数据失败!!!")return
}
1.3.4.4 更新数据
user := User{Id: 1}
if err := o.Read(&user); err == nil {user.Age = 30num, err := o.Update(&user)if err != nil {logs.Error("更新数据失败!!!")return
}
}
1.3.4.5 删除数据
// 根据id字段删除数据
num, _ := o.Delete(&User{Id: 1})
1.3.5 高级查询(QueryTable)
qs := o.QueryTable("user")// 条件查询
qs = qs.Filter("username", "test") // WHERE username = 'test'
qs = qs.Filter("age__gt", 18) // WHERE age > 18
qs = qs.Filter("age__in", 18, 20, 22) // WHERE age IN (18, 20, 22)
qs = qs.Filter("username__contains", "test") // WHERE username LIKE '%test%'
qs = qs.Filter("username__startswith", "test") // WHERE username LIKE 'test%'
qs = qs.Filter("username__endswith", "test") // WHERE username LIKE '%test'
qs = qs.Filter("profile__isnull", true) // WHERE profile_id IS NULL// 排序
qs = qs.OrderBy("age", "-username") // ORDER BY age ASC, username DESC// 分页
qs = qs.Limit(10).Offset(20) // LIMIT 10 OFFSET 20// 聚合
count, _ := qs.Count() // SELECT COUNT(*) FROM user
sum, _ := qs.Sum("age") // SELECT SUM(age) FROM user
avg, _ := qs.Avg("age") // SELECT AVG(age) FROM user
min, _ := qs.Min("age") // SELECT MIN(age) FROM user
max, _ := qs.Max("age") // SELECT MAX(age) FROM user
1.3.6 关联关系
1.3.6.1 一对一
type Profile struct {Id intAge intUser *User `orm:"reverse(one)"`
}type User struct {Id intProfile *Profile `orm:"null;rel(one);on_delete(set_null)"`
}
1.3.6.2 一对多
type Post struct {Id intTitle stringUser *User `orm:"rel(fk)"`
}type User struct {Id intPosts []*Post `orm:"reverse(many)"`
}
1.3.6.3 多对多
type User struct {Id intRoles []*Role `orm:"rel(m2m)"`
}type Role struct {Id intUsers []*User `orm:"reverse(many)"`
}
1.3.6.4 关联操作
// 一对多
user := User{Id: 1}
posts := []*Post{{Title: "Post 1"},{Title: "Post 2"},
}
o.InsertMulti(len(posts), posts)// 多对多
role := Role{Id: 1}
m2m := o.QueryM2M(&role, "Users")
m2m.Add(&User{Id: 1})
1.3.7 事务处理(Begin&Rollback&Commit)
o := orm.NewOrm()
err := o.Begin()// 事务操作
user := User{Username: "test"}
_, err = o.Insert(&user)
if err != nil {o.Rollback()return err
}profile := Profile{User: &user}
_, err = o.Insert(&profile)
if err != nil {o.Rollback()return err
}return o.Commit()
1.3.8 支持原生sql(Raw)
// 执行原生SQL
o.Raw("UPDATE user SET name = ? WHERE id = ?", "test", 1).Exec()// 查询
var users []User
num, err := o.Raw("SELECT * FROM user WHERE age > ?", 18).QueryRows(&users)// 单行查询
var user User
err := o.Raw("SELECT * FROM user WHERE id = ?", 1).QueryRow(&user)
1.3.9 表结构同步
// 自动创建表
// force: 是否强制删除重建
// verbose: 是否打印执行日志
_ = orm.RunSyncdb("default", false, true)
1.3.10 连接池配置
// 设置最大空闲连接
orm.SetMaxIdleConns("default", 30)// 设置最大打开连接
orm.SetMaxOpenConns("default", 100)
1.3.11 性能优化
- 使用 Filter 替代 Exclude,后者性能较差
- 批量操作时使用 InsertMulti
- 避免 N+1 查询,使用 RelatedSel 预加载关联数据
- 复杂查询考虑使用原生 SQL
- 合理设置连接池大小
1.3.12 调试
// 开启调试模式
orm.Debug = true// 查看最后执行的SQL
lastQuery := o.LastQuery()
1.3.13 常见问题
1.3.13.1 表名冲突
实现 TableName 方法自定义表名:
func (u *User) TableName() string {return "users"
}
1.3.13.2 字段映射问题
确保数据库字段名与结构体字段名一致,或使用 column 标签
type User struct {UserName string `orm:"column(username)"`
}
1.3.13.3 时区问题
orm.RegisterDataBase("default", "mysql", "user:password@tcp(127.0.0.1:3306)/db_name?charset=utf8&loc=Local")