Gorm是Go語言的一個orm框架,類似Java中的JPA的實現(Hibernate、EclipseLink等)。
本文目的
本文就是按照官網官方說明,自己動手嘗試下,增加記憶,僅此而已。
安裝
進入專案目錄安裝gorm
➜ Go-Gorm-Notes git:(main) ✗ go get -u gorm。io/gormgo: added github。com/jinzhu/inflection v1。0。0go: added github。com/jinzhu/now v1。1。5go: added gorm。io/gorm v1。23。10
我用的資料庫是mysql,所以還需要引入Mysql驅動
➜ Go-Gorm-Notes git:(main) ✗ go get -u gorm。io/driver/mysqlgo: added github。com/go-sql-driver/mysql v1。6。0go: added gorm。io/driver/mysql v1。3。6
建立連線
下面程式碼是建立一個Mysql的gorm。DB,之後的操作都要使用這個DB。
package modelsimport ( “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 modelsimport “gorm。io/gorm”type Author struct { gorm。Model Name string}
main方法中使用來自動建立資料庫表
package mainimport “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 modelsimport “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 modelstype 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:‘男’”`
index
Name 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 modelsimport “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 modelsimport “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
待更新。。。