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語句了。