Go语言Gorm框架学习笔记
Gorm是Go语言的一个orm框架,类似Java中的JPA的实现(Hibernate、EclipseLink等)。 本文目的
本文就是按照官网官方说明,自己动手尝试下,增加记忆,仅此而已。 安装
进入项目目录安装gorm ➜ Go-Gorm-Notes git:(main) ✗ go get -u gorm.io/gorm go: added github.com/jinzhu/inflection v1.0.0 go: added github.com/jinzhu/now v1.1.5 go: added gorm.io/gorm v1.23.10
我用的数据库是mysql,所以还需要引入Mysql驱动 ➜ Go-Gorm-Notes git:(main) ✗ go get -u gorm.io/driver/mysql go: added github.com/go-sql-driver/mysql v1.6.0 go: added gorm.io/driver/mysql v1.3.6创建连接
下面代码是创建一个Mysql的gorm.DB,之后的操作都要使用这个DB。 package models import ( "gorm.io/driver/mysql" "gorm.io/gorm" ) var Db = initDb() //初始化数据库连接 func initDb() *gorm.DB { // Mysql的链接字符串,我电脑上用户名是root,密码是qwe!@#123 dsn := "root:qwe!@#123@tcp(127.0.0.1:3306)/go-gorm?charset=utf8mb4&parseTime=True&loc=Local" // Mysql驱动有自己的配置选项,可以通过 mysql.New(mysql.Config{})配置。具体可看mysql.Config。 Db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{}) return Db } Model
对于这种ORM框架,Model是特别重要的,也是值得去深入学习的地方,因为一个小问题,可能就会引发数据库的问题。 初识
我会创建一个简单的Model,并使用gorm的自动创建数据库表功能,来看看如何做到通过Model自动创建表。
创建一个Author结构体 package models import "gorm.io/gorm" type Author struct { gorm.Model Name string }
main方法中使用来自动创建数据库表 package main import "Go-Gorm-Notes/models" func main() { // 使用AutoMigrate自动创建数据库表 models.Db.AutoMigrate(&models.Author{}) }
运行后会发现数据库中多了一个叫做authors的表。请注意这个名字,这是gorm自动创建的,能否自己指定呢?肯定是可以的,看下自动创建的表的结构如下: create table authors ( id bigint unsigned auto_increment primary key, created_at datetime(3) null, updated_at datetime(3) null, deleted_at datetime(3) null, name longtext null ); create index idx_authors_deleted_at on authors (deleted_at);
说明:id,created_at,updated_at,deleted_at都是因为Author结构体继承了gorm.Model。这是gorm自身提供的,我们也可以不使用它,如果不用就要自己定义主键字段。
另外name字段是自己加的,但是name字段的类型是longtext,这可能不是我们想要的,我们可能想要的是name是varchar(200)这样的类型,也是可以自定义的。官网都有说明,接下来我一一尝试下,并记录下来。 自定义表名
自定义表名需要实现gorm.schema下的TableName方法。 package models import "gorm.io/gorm" type Author struct { gorm.Model Name string } // TableName 自定义表名 func (Author) TableName() string { return "author" }
重新运行看看是否会自动创建author表
模型定义字段标签
可以在结构体字段名后面使用gorm:xxx的机构来配置标签,从而达到自定义数据库列信息的效果。
声明 model 时,tag 是可选的,GORM 支持以下 tag: tag 名大小写不敏感,但建议使用 camelCase 风格
标签名
说明
column
指定 db 列名
type
列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
serializer
指定将数据序列化或反序列化到数据库中的序列化器, 例如: serializer:json/gob/unixtime
size
定义列数据类型的大小或长度,例如 size: 256
primaryKey
将列定义为主键
unique
将列定义为唯一键
default
定义列的默认值
precision
specifies column precision
scale
specifies column scale
not null
specifies column as NOT NULL
autoIncrement
specifies column auto incrementable
autoIncrementIncrement
auto increment step, controls the interval between successive column values
embedded
embed the field
embeddedPrefix
column name prefix for embedded fields
autoCreateTime
track current time when creating, for int fields, it will track unix seconds, use value nano/milli to track unix nano/milli seconds, e.g: autoCreateTime:nano
autoUpdateTime
track current time when creating/updating, for int fields, it will track unix seconds, use value nano/milli to track unix nano/milli seconds, e.g: autoUpdateTime:milli
index
create index with options, use same name for multiple fields creates composite indexes, refer Indexes for details
uniqueIndex
same as index, but create uniqued index
check
creates check constraint, eg: check:age > 13, refer Constraints
<-
set field’s write permission, <-:create create-only field, <-:update update-only field, <-:false no write permission, <- create and update permission
->
set field’s read permission, ->:false no read permission
-
ignore this field, - no read/write permission, -:migration no migrate permission, -:all no read/write/migrate permission
comment
add comment for field when migration column
定义列的名字,比如如下代码将Name字段对应的数据库列名为t_name。 Name string `gorm:"column:t_name"`type
列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
比如我继续设置Name字段为varchar(200) not null default "" Name string `gorm:"column:name;type:varchar(200) not null default """`
可以看到类型等信息已经正确设置。 size
定义列数据类型的大小或长度,例如 size: 256 Sex string `gorm:"size:10"`
这里我没有使用name字段,是因为Name字段制定了type,类型varchar(200),再指定size无效。 primarykey
上面的结构体我使用了gorm.Model,gorm自动给我生成了主键,现在我要自己定义主键,重新定义下结构体 package models type Author struct { ID uint `gorm:"primarykey"` Name string `gorm:"column:name;type:varchar(200) not null default "";"` Sex string `gorm:"size:10"` } // TableName 自定义表名 func (Author) TableName() string { return "author" }
我使用 ID uint `gorm:"primarykey"`
定义ID是主键。
unique
使用unique就会设置唯一索引。 Name string `gorm:"column:name;type:varchar(200) not null default "";unique"`
结果如下:
default
设置默认值 Sex string `gorm:"size:10;default:"男""`
indexName string `gorm:"column:name;type:varchar(200) not null default "";index"`
创建了一个普通索引。 uniqueIndex
创建唯一索引 // 身份信息唯一 Identify string `gorm:"size:100;uniqueIndex"`
需要注意的是上面的size:100;不能去掉,使用它可以是数据库类型变为varchar,否则类型是longtext,这个类似不能加唯一索引的。会报错。
not null
指定列不能为空 Identify string `gorm:"size:100;uniqueIndex;not null;"`
autoCreateTime
创建记录时自动填充时间,取值nano或者milli。
插入一条记录 models.Db.Save(&models.Author{Name: "张飞", Identify: "001"})
结果是:
id
name
sex
identify
ct_time_nano
ct_time_milli
ct_nano
ct_milli
1
张飞
男
001
2022-10-07 12:11:47.854
2022-10-07 12:11:47.854
1665115907854000000
1665115907854 autoUpdateTime
跟autoCreateTime类似。 embedded
内嵌字段,将一个结构体嵌入进来 package models import "time" type Author struct { ID uint `gorm:"primarykey"` Name string `gorm:"column:name;type:varchar(200) not null default "";index"` Sex string `gorm:"size:10;default:"男""` // 身份信息唯一 Identify string `gorm:"size:100;uniqueIndex;not null;"` CtTimeNano time.Time `gorm:"autoCreateTime:nano"` //nano/milli CtTimeMilli time.Time `gorm:"autoCreateTime:milli"` CtNano int `gorm:"autoCreateTime:nano"` CtMilli int `gorm:"autoCreateTime:milli"` ConcatWay `gorm:"embedded"` } // ConcatWay 联系方式 type ConcatWay struct { Address string Phone string Email string } // TableName 自定义表名 func (Author) TableName() string { return "author" }
运行AutoMigrate后,数据库表结构如下
增加了Address结构体下的字段。 embeddedPrefix
对于内嵌的结构体字段,增加前缀,默认是空 ConcatWay `gorm:"embedded;embeddedPrefix:cw_"`
comment
字段的备注信息 ID uint `gorm:"primarykey;comment:主键ID"`
serializer
指定将数据序列化或反序列化到数据库中的序列化器, 例如: serializer:json/gob/unixtime ByteJson []byte `gorm:"serializer:json"` ConcatWayJSON ConcatWay `gorm:"serializer:json"` ConcatWayGob ConcatWay `gorm:"serializer:gob"` TimeUnixtime int64 `gorm:"serializer:unixtime;type:time"` //将int64的内容转化为ddatetime存储
存储一条数据 models.Db.Create(&models.Author{ Name: "张飞", Identify: "001", ByteJson: []byte("字节切片"), ConcatWayJSON: models.ConcatWay{Address: "https://itlab1024.com", Email: "itlab1024@163.com"}, ConcatWayGob: models.ConcatWay{Address: "https://itlab1024.com", Email: "itlab1024@163.com"}, TimeUnixtime: 12, })
id
name
sex
identify
ct_time_nano
ct_time_milli
ct_nano
ct_milli
cw_address
cw_phone
cw_email
byte_json
concat_way_json
concat_way_gob
time_unixtime
1
张飞
男
001
2022-10-07 14:27:01.859
2022-10-07 14:27:01.859
1665124021859000000
1665124021859
"5a2X6IqC5YiH54mH"
{"Address":"https://itlab1024.com","Phone":"","Email":"itlab1024@163.com"}
0x37FF8103010109436F6E63617457617901FF82000103010741646472657373010C00010550686F6E65010C000105456D61696C010C0000002DFF82011568747470733A2F2F69746C6162313032342E636F6D021169746C616231303234403136332E636F6D00
1970-01-01 08:00:12 autoIncrement
设置列自增,需要与type标签联合使用 autoIncrementIncrement
设置列自增步长,需要与type标签联合使用 unique
设置唯一键 check
设置约束,比如设置name的值不能等于abc Name string `gorm:"check:name <> "abc""`关联Belongs To
belongs to 会与另一个模型建立了一对一的连接。 这种模型的每一个实例都"属于"另一个模型的一个实例。就是谁属于谁,比如一个人属于一个国家。
看如下如下两个结构体User和Country package models import "gorm.io/gorm" type User struct { gorm.Model Name string CountryId uint // 这里不能使用匿名 Country Country } type Country struct { *gorm.Model Name string }
自动创建表后,可以得到如下结构
用户表的country_id和country表的id关联了起来。一对一的关系。 Has One
has one 与另一个模型建立一对一的关联,但它和一对一关系有些许不同。 这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例。
例如,您的应用包含 user 和 credit card 模型,且每个 user 只能有一张 credit card。 // User 有一张 CreditCard,UserID 是外键 type User struct { gorm.Model CreditCard CreditCard } type CreditCard struct { gorm.Model Number string UserID uint }
可以看到users表没有credit的相关字段。
再看下credit_cards表
该表的userId关联到了user表的ID字段。 Has Many
类似于has one,只不过这里要使用的是切片 // User 有多张 CreditCard,UserID 是外键 type User struct { gorm.Model CreditCards []CreditCard } type CreditCard struct { gorm.Model Number string UserID uint }
创建出来的表如下:
users表:
credit_cards表如下:
跟has one创建的表结构是一样的。 Many To Many
Many to Many 会在两个 model 中添加一张连接表,可以通过标签many2manay设置关联表的名字。 // User 拥有并属于多种 language,`user_languages` 是连接表 type User struct { gorm.Model Languages []Language `gorm:"many2many:user_languages;"` } type Language struct { gorm.Model Name string }
会创建user_languages中间表,并且关联表中的user_id跟User表的ID关联,language_id跟languages表的id关联。
上面的都是使用默认的情况,比如外键名称等,如果想更换名字等信息,就得重写外键,这里我就一一说明了。 原生SQL
待更新...