在介紹 GORM 之前,先來看看什麼是 ORM~
官網:https://gorm.io/index.html
ORM 是 Object Relational Mapping(物件關聯對映)。目的就是「 用物件導向的方式來操作資料庫 」,而不寫 SQL。
Object(物件)
對應到 Go 的話,就是 struct
,可以理解為程式的物件模型,例如 To-do List 的 Task:
type Task struct {
ID uint
Item string
Status bool
}
Relational(關聯)
SQLite / MySQL / Postgres 都是關聯式資料庫!
資料是用 表格(Table) 來表示的:
CREATE TABLE tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
item TEXT,
status BOOLEAN
);
Mapping(對映)
ORM 就是把 程式中的物件 ↔ 資料庫中的表格 做「一對一的映射」。
意思就是:
我們來看看以一般的 SQL 操作和使用 ORM 操作的差別:
一般 SQL
每一次的查詢、更新、新增 都要寫 SQL 才能完成。且每次都要自己拼 SQL,容易出錯之外,只要欄位改變,SQL + Scan()
也都要改。最重要的是 SQL 跟程式綁死了,非常不好閱讀!
例如:
// 新增 task
stmt, _ := db.Prepare("INSERT INTO tasks(item, status) VALUES (?, ?)")
stmt.Exec("買牛奶", false)
// 查詢
rows, _ := db.Query("SELECT id, item, status FROM tasks")
for rows.Next() {
var id int
var item string
var status bool
rows.Scan(&id, &item, &status)
fmt.Println(id, item, status)
}
ORM(GORM)
我們一樣新增、查詢 Task,同樣的操作,用 ORM 寫就變得簡單很多,原因是我們不用再多寫 SQL,而是直接用物件來存取資料,剩下的 GORM 會自動幫你完成。
例如:
// 定義 struct
type Task struct {
id uint
item string
status bool
}
// 新增 task
db.Create(&Task{item: "買牛奶", status: false})
// 查詢
var tasks []Task
db.Find(&tasks)
fmt.Println(tasks)
因為 GORM 是目前 Go 最熱門的 ORM,原因是它把「 程式中的物件 」和「 資料庫 」整合得很好。
以下是 GOR
CRUD(Create/Read/Update/Delete)
db.Create(&tasks) // 新增
db.First(&tasks, 1) // 讀取 (id=1)
db.Model(&tasks).Update("status", true) // 更新
db.Delete(&tasks) // 刪除
Migration
可以自動建表或更新欄位。
db.AutoMigrate(&Task{})
條件查詢
db.Where("status = ?", false).Find(&tasks)
關聯模型
跨資料庫支援
換成 MySQL、Postgres 資料庫也幾乎不用改程式碼。
常用指令對照表:
Create:
動作 | SQL | GORM |
---|---|---|
新增一筆資料 | INSERT INTO users (id, item, status) VALUES (1, "寫鐵人賽文章", false); |
db.Create(&Task{ID: 1, Item: "寫鐵人賽文章", Status: false}) |
Read:
動作 | SQL | GORM |
---|---|---|
查第一筆 (id=1) | SELECT * FROM tasks WHERE id = 1 LIMIT 1; |
db.First(&tasks, 1) |
查第一筆符合條件 | SELECT * FROM tasks WHERE item = "鐵人賽" LIMIT 1; |
db.First(&tasks, "item = ?", "鐵人賽") |
查全部 | SELECT * FROM tasks; |
db.Find(&tasks) |
條件查詢 | SELECT * FROM tasks WHERE id > 18; |
db.Where("id > ?", 18).Find(&tasks) |
排序 | SELECT * FROM tasks ORDER BY id DESC; |
db.Order("id desc").Find(&tasks) |
限制筆數 | SELECT * FROM tasks LIMIT 10; |
db.Limit(10).Find(&tasks) |
分頁 | SELECT * FROM tasks LIMIT 10 OFFSET 20; |
db.Limit(10).Offset(20).Find(&tasks) |
Update:
動作 | SQL | GORM |
---|---|---|
更新單一欄位 | UPDATE tasks SET status = true WHERE id = 1; |
db.Model(&tasks).Update("status", true) |
更新多個欄位 | UPDATE tasks SET item = "寫日記", status = false WHERE id = 1; |
db.Model(&tasks).Updates(Task{Item: "寫日記", Status: false}) |
條件更新 | UPDATE tasks SET status = false WHERE item = "寫日記"; |
db.Model(&Task{}).Where("item = ?", "寫日記").Update("id", 40) |
Delete:
動作 | SQL | GORM |
---|---|---|
刪除一筆 | DELETE FROM tasks WHERE id = 1; |
db.Delete(&tasks) |
條件刪除 | DELETE FROM tasks WHERE id < 5; |
db.Where("id < ?", 5).Delete(&Task{}) |
但即便如此方便,也不是每個人都會使用~ 畢竟它還是有一些缺點在:
明天開始就會一步步的修改 To-do List ,讓它可以直接把資料存入資料庫中。