Go 語言系列(十四):ORM 與資料庫工具 — GORM vs sqlx
這是 Go 語言從零到 Web 應用系列的第十四篇。前面我們用 database/sql 手寫 SQL 操作資料庫,現在來看看 ORM 和資料庫工具如何簡化這些工作。 ORM vs 原生 SQL 面向 原生 SQL (database/sql) ORM (GORM) SQL-first (sqlx) 學習曲線 需要懂 SQL 可以少寫 SQL 需要懂 SQL 開發速度 較慢(模板程式碼多) 快(自動產生 SQL) 中等 SQL 控制力 完全控制 有限(複雜查詢困難) 完全控制 效能 最佳 有反射開銷 接近原生 Migration 需自行處理 內建 AutoMigrate 需自行處理 GORM 安裝: go get -u gorm.io/gorm go get -u gorm.io/driver/sqlite # 或 postgres、mysql Model 定義 package main import ( "time" "gorm.io/gorm" ) type User struct { ID uint `gorm:"primaryKey" json:"id"` Name string `gorm:"size:100;not null" json:"name"` Email string `gorm:"uniqueIndex;not null" json:"email"` Books []Book `gorm:"foreignKey:UserID" json:"books"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 軟刪除 } type Book struct { ID uint `gorm:"primaryKey" json:"id"` Title string `gorm:"size:200;not null" json:"title"` Author string `gorm:"size:100" json:"author"` UserID uint `json:"user_id"` } 連線與 AutoMigrate import ( "gorm.io/driver/sqlite" "gorm.io/gorm" ) func main() { db, err := gorm.Open(sqlite.Open("app.db"), &gorm.Config{}) if err != nil { panic("failed to connect database") } // AutoMigrate 自動建立或更新表結構 db.AutoMigrate(&User{}, &Book{}) } CRUD 操作 // Create user := User{Name: "Jack", Email: "[email protected]"} result := db.Create(&user) // result.RowsAffected = 1 // user.ID 自動填入 // Read var u User db.First(&u, 1) // 找 ID=1 db.Where("email = ?", "[email protected]").First(&u) // 條件查詢 // 查詢多筆 var users []User db.Where("name LIKE ?", "%Jack%").Find(&users) // Update db.Model(&user).Update("name", "Jack Tse") db.Model(&user).Updates(User{Name: "Jack Tse", Email: "[email protected]"}) // Delete(軟刪除,因為 User 有 DeletedAt 欄位) db.Delete(&user, 1) // 真正刪除 db.Unscoped().Delete(&user, 1) 關聯查詢 // 建立使用者和書籍 db.Create(&User{ Name: "Jack", Email: "[email protected]", Books: []Book{ {Title: "Go in Action", Author: "William Kennedy"}, {Title: "The Go Programming Language", Author: "Donovan & Kernighan"}, }, }) // Preload 關聯資料 var user User db.Preload("Books").First(&user, 1) // user.Books 會自動填入 // 條件 Preload db.Preload("Books", "author LIKE ?", "%Kennedy%").First(&user, 1) Hook // 在建立之前自動處理 func (u *User) BeforeCreate(tx *gorm.DB) error { if u.Email == "" { return errors.New("email is required") } return nil } // 在刪除之後清理關聯 func (u *User) AfterDelete(tx *gorm.DB) error { tx.Where("user_id = ?", u.ID).Delete(&Book{}) return nil } Transaction err := db.Transaction(func(tx *gorm.DB) error { user := User{Name: "Jack", Email: "[email protected]"} if err := tx.Create(&user).Error; err != nil { return err // 回傳 error 會自動 rollback } book := Book{Title: "New Book", UserID: user.ID} if err := tx.Create(&book).Error; err != nil { return err } return nil // 回傳 nil 會自動 commit }) sqlx 安裝: ...