Golang下的ORM框架gorm的介绍和使用
前言:gorm是Golang语言中一款性能极好的ORM库,对开发人员相对是比较友好的。当然还有另外一个xorm库也是比较出名的,感兴趣的也可以看看这个库,接下来主要介绍下
gorm库的一些基本使用。
GORM介绍和快速入门
功能概览
- 全功能ORM(无限接近)
- 关联(Has One, Has Many, Belongs To, Many To Many, 多态)
- 钩子函数Hook(在创建/保存/更新/删除/查找之前或之后)
- 预加载
- 事务
- 复合主键
- SQL 生成器
- 数据库自动迁移
- 自定义日志
- 可扩展性, 可基于 GORM 回调编写插件
- 所有功能都被测试覆盖
- 开发者友好
安装
我们都知道,在golang中需要使用一些驱动包来对指定数据库进行操作,比如MySQL需要使用github.com/go-sql-driver/mysql库,而Sqlite需要使用github.com/mattn/go-sqlite3库来支持,不过好在gorm框架中对各个驱动包进行了简单包装,可以让我们在写程序时可以更方便的管理驱动库.
支持的数据库以及导入路径如下:
- mysql: github.com/jinzhu/gorm/dialects/mysql
- postgres: github.com/jinzhu/gorm/dialects/postgres
- sqlite: github.com/jinzhu/gorm/dialects/sqlite
- sqlserver: github.com/jinzhu/gorm/dialects/mssql
注意:gorm框架只是简单封装了数据库的驱动包,在安装时仍需要下载原始的驱动包
vim
复制代码
# 由于在项目中使用mysql比较多,这里使用mysql进行数据存储$ go get -u github.com/jinzhu/gorm$ go get -u github.com/go-sql-driver/mysql
快速入门
reasonml
复制代码
# 使用docker快速创建一个本地可连接的mysql实例$ docker run -itd -e MYSQL_ROOT_PASSWORD='bgbiao.top' --name go-orm-mysql -p 13306:3306 mysql:5.6# 登陆mysql并创建一个测试库$ docker exec -it go-orm-mysql mysql -uroot -pbgbiao.top....mysql> create database test_api;Query OK, 1 row affected (0.00 sec)mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || test_api |+--------------------+4 rows in set (0.00 sec)# 运行一个简单示例$ cat gorm-mysql-example.gopackage mainimport ( "fmt" "time" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql")// 定义一个数据模型(user表)// 列名是字段名的蛇形小写(PassWd->pass_word)type User struct { Id uint `gorm:"AUTO_INCREMENT"` Name string `gorm:"size:50"` Age int `gorm:"size:3"` Birthday *time.Time Email string `gorm:"type:varchar(50);unique_index"` PassWord string `gorm:"type:varchar(25)"`}var db *gorm.DBfunc main() { db,err := gorm.Open("mysql","root:bgbiao.top@(127.0.0.1:13306)/test_api?charset=utf8&parseTime=True&loc=Local") if err != nil { fmt.Errorf("创建数据库连接失败:%v",err) } defer db.Close() // 自动迁移数据结构(table schema) // 注意:在gorm中,默认的表名都是结构体名称的复数形式,比如User结构体默认创建的表为users // db.SingularTable(true) 可以取消表名的复数形式,使得表名和结构体名称一致 db.AutoMigrate(&User{}) // 添加唯一索引 db.Model(&User{}).AddUniqueIndex("name_email", "id", "name","email") // 插入记录 db.Create(&User{Name:"bgbiao",Age:18,Email:"bgbiao@bgbiao.top"}) db.Create(&User{Name:"xxb",Age:18,Email:"xxb@bgbiao.top"}) var user User var users []User // 查看插入后的全部元素 fmt.Printf("插入后元素:\n") db.Find(&users) fmt.Println(users) // 查询一条记录 db.First(&user,"name = ?","bgbiao") fmt.Println("查看查询记录:",user) // 更新记录(基于查出来的数据进行更新) db.Model(&user).Update("name","biaoge") fmt.Println("更新后的记录:",user) // 删除记录 db.Delete(&user) // 查看全部记录 fmt.Println("查看全部记录:") db.Find(&users) fmt.Println(users)}# 运行gorm实例$ go run gorm-mysql-example.go插入后元素:[{1 bgbiao 18 <nil> bgbiao@bgbiao.top } {2 xxb 18 <nil> xxb@bgbiao.top }]查看查询记录: {1 bgbiao 18 <nil> bgbiao@bgbiao.top }更新后的记录: {1 biaoge 18 <nil> bgbiao@bgbiao.top }查看全部记录:[{2 xxb 18 <nil> xxb@bgbiao.top }]
GORM常用的功能函数
自动迁移
注意: 使用自动迁移模式将保持表的更新,但是不会更新索引以及现有列的类型或删除未使用的列
awk
复制代码
// 同时迁移多个模型db.AutoMigrate(&User{}, &Product{}, &Order{})// 创建表时增加相关参数// 比如修改表的字符类型CHARSET=utf8db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})
检查表
awk
复制代码
// 检查模型是否存在db.HasTable(&User{})// 检查表是否存在db.HasTable("users")
增、删、改表结构
注意:在实际企业的生产环境中,通常数据库级别的变更操作,都需要转换成sql交由DBA兄弟帮忙进行线上库表变更,因此不论使用自动迁移,还是手动创建表,都是在开发环境阶段的
awk
复制代码
// 使用模型创建db.CreateTable(&User{})// 增加参数创建db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&User{})// 删除表db.DropTable(&User{})db.DropTable("users")// 模型和表名的混搭db.DropTableIfExists(&User{}, "products")// 修改列(修改字段类型)db.Model(&User{}).ModifyColumn("description", "text")// 删除列db.Model(&User{}).DropColumn("description")// 指定表名创建表db.Table("deleted_users").CreateTable(&User{})// 指定表名查询var deleted_users []Userdb.Table("deleted_users").Find(&deleted_users)
索引和约束
awk
复制代码
// 添加外键// 1st param : 外键字段// 2nd param : 外键表(字段)// 3rd param : ONDELETE// 4th param : ONUPDATEdb.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")// 单个索引db.Model(&User{}).AddIndex("idx_user_name", "name")// 多字段索引db.Model(&User{}).AddIndex("idx_user_name_age", "name", "age")// 添加唯一索引(通常使用多个字段来唯一标识一条记录)db.Model(&User{}).AddUniqueIndex("idx_user_name", "name")db.Model(&User{}).AddUniqueIndex("idx_user_name_age", "name", "id","email")// 删除索引db.Model(&User{}).RemoveIndex("idx_user_name")
GORM模型注意事项
gorm.Model结构体
其实在gorm官方文档的示例中,会默认在模型的属性中增加一个gorm.Model的属性,该属性的原始结构如下:
elm
复制代码
// 官方示例模型type User struct { gorm.Model Name string .....}// gorm.Model结构体type Model struct { ID uint `gorm:"primary_key"` CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time `sql:"index"`}
很明显,当我们在用户自定义的模型中增加gorm.Model时,会自动为我们的表增加id,created_at,updated_at,deleted_at四个字段。
同时需要注意的是,当我们的模型中有CreatedAt,UpdatedAt,DeletedAt属性并且类型为time.Time或者*time.Time类型时,当有数据操作时,会自动更新对应的时间。
所以,在定义模型时,可以根据实际的需求来决定是否引入gorm.Model结构
另外需要注意的是: 所有字段的零值, 比如0, '', false 或者其它零值都不会保存到数据库内,但会使用他们的默认值,因此一些非必须字段,可以使用DEFAULT的tag字段来声明列的默认值。
gorm模型支持的tags
注意:gorm支持一些常见的tags来自定义模型字段的扩展信息
| 结构体标记 | 描述 |
|---|---|
| column | 列明(默认是字段的蛇形小写) |
| type | 数据类型 |
| size | 列长度 |
| PRIMARY_KEY | 声明主键 |
| UNIQUE | 声明唯一 |
| DEFAULT | 指定默认值 |
| PRECISION | 声明列精度 |
| NOT NULL | 将列指定为非 NULL |
| AUTO_INCREMENT | 声明自增列 |
| INDEX | 创建具有或不带名称的索引, 如果多个索引同名则创建复合索引 |
| UNIQUE_INDEX | 创建唯一索引 |
| EMBEDDED | 将结构设置为嵌入 |
| EMBEDDED_PREFIX | 设置嵌入结构的前缀 |
| - | 忽略此字段 |
注意: gorm也支持一些关联的结构体标签,比如外键,关联外键,等操作,通常在复杂的企业环境中,建议在库表设计时将相关表都设计成孤立表,具体的关联逻辑由业务层去实现(可能增加了开发的成本,不过当业务发展比较复杂时,这样做无疑是方便后期做扩展和优化的)