Golang ORM類庫:GORM的使用總結
Golang ORM類庫:GORM的使用總結
技術概述
ORM(Object Relation Mapping 關係物件對映),就是把物件模型表示的物件對映到基於SQL的關係模型資料庫結構中,在具體的操作實體物件的時候,不需要直接與複雜的 SQL語句打交道,只需簡單的操作實體物件的屬性和方法。而GORM就是基於Go語言實現的ORM庫。在使用Go語言開發專案的時候,我們可以利用GORM來實現對資料庫的操作,進行簡單的CRUD操作。
技術詳述
使用流程
使用GORM
1.匯入GROM和資料庫驅動
可以使用一下命令安裝GROM和資料庫驅動
go get -u gorm.io/gorm go get -u gorm.io/driver/mysql
但是這是一種比較傳統的方法。我們還可以在專案中使用go.mod檔案設定專案需要新增的依賴包:
go 1.15
require (
gorm.io/driver/mysql v1.0.5
gorm.io/gorm v1.21.8
)
像上面這樣定義好需要新增的依賴包之後,就可以直接執行下面這一條指令讓go.mod檔案自動引入所有依賴包:
go mod download
執行完上述指令若沒有任何反應則說明已經成功將GORM和資料庫驅動的依賴包匯入了
2.定義資料庫連線資訊
在專案中的.env檔案中編寫資料庫連線的資訊,可以大致按照如下格式編寫,但需要根據具體專案要求修改具體資訊,比如這裡使用的資料庫是MySQL的,如果使用的是其他資料庫(PostgreSQL等),則需要修改MYSQL_DSN的內容:
MYSQL_DSN="root:12345678@tcp(localhost:3306)/pingleme?charset=utf8&parseTime=True&loc=Local" REDIS_ADDR="pingleme.top:6379" REDIS_PW="Test1234" REDIS_DB="" SESSION_SECRET="setOnProducation" GIN_MODE="debug" LOG_LEVEL="debug" LOG_PATH="./.log/system.log" LOG_MAX_SIZE="50" LOG_MAX_AGE="30" LOG_MAX_BACKUP="0" LOG_COMPRESS="false" LOG_JSON_FORMAT="false" LOG_SHOW_LINES="true" LOG_SHOW_IN_CONSOLE="true" DB_LOG_LEVEL="info"
在這裡可能會遇到一些連線問題,會在之後的“遇到的問題和解決過程”模組解釋
3.獲取資料庫連線
完成以上準備工作後,需要先獲取資料庫的連線:
package main
import (
"gorm.io/gorm"
"gorm.io/driver/mysql"
)
func main() {
db, err := gorm.Open("mysql", &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
defer db.Close()
db.SingularTable(true)
}
4.定義資料庫模型
GORM 傾向於約定,而不是配置。預設情況下,GORM 使用 ID 作為主鍵,使用結構體名的 蛇形複數 作為表名,欄位名的 蛇形 作為列名,並使用 CreatedAt、UpdatedAt 欄位追蹤建立、更新時間。
定義資料庫模型就是將資料庫的表結構對應到struct中,比如如下的使用者表表結構:
CREATE TABLE `users` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`uid` varchar(191) NOT NULL,
`password_digest` longtext NOT NULL,
`user_name` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid` (`uid`),
) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
可以定義對應的struct:
// User 使用者模型
type User struct {
gorm.Model
UID string `gorm:"not null;unique"`
PasswordDigest string `gorm:"not null"`
UserName string `gorm:"type:varchar(20);not null"`
}
struct的每個欄位都對應著資料庫表中的欄位,而資料庫欄位的屬性則由gorm宣告的結構標記來定義。比如,"type:varchar(20)"定義了欄位的型別與長度、"not null"則聲明瞭欄位是非空的,這些都與資料庫中的宣告一一對應。更多的屬性定義可以檢視官方文件給出的GORM模型定義。
5.CRUD操作
5.1 建立
user := User{UID: "221801114", PasswordDigest: "123456", UserName: "silicon"}
result := db.Create(&user) // 通過資料的指標來建立
user.ID // 返回插入資料的主鍵
result.Error // 返回 error
result.RowsAffected // 返回插入記錄的條數
5.2 查詢
// 獲取第一條記錄(主鍵升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;
// 獲取一條記錄,沒有指定排序欄位
db.Take(&user)
// SELECT * FROM users LIMIT 1;
// 獲取最後一條記錄(主鍵降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
// 獲取全部記錄
result := db.Find(&users)
// SELECT * FROM users;
result := db.First(&user)
result.RowsAffected // 返回找到的記錄數
result.Error // returns error
// 檢查 ErrRecordNotFound 錯誤
errors.Is(result.Error, gorm.ErrRecordNotFound)
5.3 更新
db.First(&user)
user.PasswordDigest = "12345678"
db.Save(&user)
// UPDATE users SET uid='221801114', passworddigest="12345678", birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=1;
5.4 刪除
刪除記錄時需要帶主鍵,否則會導致批量刪除:
// user 的 ID 是 `1`
db.Delete(&user)
// DELETE from users where id = 1;
// 帶額外條件的刪除
db.Where("uid = ?", "221801114").Delete(&user)
// DELETE from users where id = 1 AND uid = "221801114";
遇到的問題和解決過程
1. 資料庫連線字串出錯
問題描述
當時配置資料庫資訊的時候沒有按照規範書寫連線串,導致資料庫連線失敗,錯誤程式碼如下:
MYSQL_DSN="root:12345678/pingleme?charset=utf8&parseTime=True&loc=Local"
解決
應當要將埠號等資訊放在“@tcp()”的括號中,具體可以按照如下格式修改:
MYSQL_DSN="user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
2.資料庫欄位包含sql的關鍵字
問題描述
我在設計一個數據庫表結構的時候,誤將sql語句的關鍵字"index"作為資料庫欄位的名字:
CREATE TABLE `scoring_items` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) DEFAULT NULL,
`updated_at` datetime(3) DEFAULT NULL,
`deleted_at` datetime(3) DEFAULT NULL,
`homework_id` bigint unsigned NOT NULL,
`description` varchar(255) NOT NULL,
`score` bigint NOT NULL DEFAULT '-1',
`option` tinyint NOT NULL,
`note` varchar(255) DEFAULT NULL,
`assistant_id` bigint NOT NULL,
`level` bigint NOT NULL DEFAULT '0',
`index` bigint NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_scoring_items_deleted_at` (`deleted_at`),
KEY `fk_homeworks_scoring_items` (`homework_id`),
CONSTRAINT `fk_homeworks_scoring_items` FOREIGN KEY (`homework_id`) REFERENCES `homeworks` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
以致於我對這一個資料庫表的如下查詢操作屢次失敗,找不出原因:
result = Repo.DB.Order("index desc").Where("homework_id = ?", ID).Find(&items)
解決
在使用該欄位進行查詢時,應該將該欄位的名稱包含在``之間,就可以避免與sql的衝突。比如,可以將上面的查詢操作改為如下形式:
result = Repo.DB.Order("`index` desc").Where("homework_id = ?", ID).Find(&items)
總結
通過上述的介紹,就可以大致地使用GO提供的ORM類庫GORM輕鬆的進行簡單的CRUD操作了。學會了GORM,就不需要自己維護sql語句了。