Go语言ORM框架GORM深度解析
Go语言ORM框架GORM深度解析
引言
GORM是Go语言中最流行的ORM(对象关系映射)框架,提供了强大的数据访问能力和优雅的API设计。本文将深入探讨GORM的核心功能、高级特性和最佳实践。
一、环境配置
1.1 安装GORM
go get gorm.io/gorm go get gorm.io/driver/mysql1.2 连接数据库
package main import ( "fmt" "log" "time" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" ) func main() { dsn := "user:password@tcp(localhost:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ Logger: logger.Default.LogMode(logger.Info), }) if err != nil { log.Fatalf("Failed to connect to database: %v", err) } // 获取底层sql.DB并设置连接池 sqlDB, err := db.DB() if err != nil { log.Fatalf("Failed to get sql.DB: %v", err) } sqlDB.SetMaxOpenConns(100) sqlDB.SetMaxIdleConns(20) sqlDB.SetConnMaxLifetime(time.Hour) fmt.Println("Successfully connected to database") }二、模型定义
2.1 基础模型
import ( "time" "gorm.io/gorm" ) type User struct { gorm.Model Name string `gorm:"size:100;not null"` Email string `gorm:"size:255;unique;not null"` Age int `gorm:"default:0"` Birthday *time.Time `gorm:"type:date"` Active bool `gorm:"default:true"` } type Product struct { ID uint `gorm:"primaryKey"` Name string `gorm:"size:200;not null"` Price float64 `gorm:"type:decimal(10,2)"` Stock int `gorm:"default:0"` CategoryID uint CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` }2.2 关联模型
type Category struct { ID uint `gorm:"primaryKey"` Name string `gorm:"size:100;not null"` Products []Product `gorm:"foreignKey:CategoryID"` } type Order struct { ID uint `gorm:"primaryKey"` UserID uint User User `gorm:"foreignKey:UserID"` Items []OrderItem `gorm:"foreignKey:OrderID"` TotalPrice float64 `gorm:"type:decimal(12,2)"` Status string `gorm:"size:20;default:'pending'"` } type OrderItem struct { ID uint `gorm:"primaryKey"` OrderID uint ProductID uint Product Product `gorm:"foreignKey:ProductID"` Quantity int `gorm:"default:1"` Price float64 `gorm:"type:decimal(10,2)"` }三、CRUD操作
3.1 创建记录
func CreateUser(db *gorm.DB, user *User) error { return db.Create(user).Error } func CreateUsers(db *gorm.DB, users []*User) error { return db.Create(&users).Error }3.2 查询记录
func GetUserByID(db *gorm.DB, id uint) (*User, error) { var user User err := db.First(&user, id).Error if err != nil { return nil, err } return &user, nil } func GetUsersByAge(db *gorm.DB, minAge int) ([]*User, error) { var users []*User err := db.Where("age >= ?", minAge).Order("age DESC").Find(&users).Error if err != nil { return nil, err } return users, nil } func GetUserWithPreload(db *gorm.DB, id uint) (*User, error) { var user User err := db.Preload("Orders").Preload("Orders.Items").First(&user, id).Error if err != nil { return nil, err } return &user, nil }3.3 更新记录
func UpdateUser(db *gorm.DB, id uint, updates map[string]interface{}) error { return db.Model(&User{}).Where("id = ?", id).Updates(updates).Error } func UpdateUserSelective(db *gorm.DB, user *User) error { return db.Select("Name", "Email").Updates(user).Error }3.4 删除记录
func DeleteUser(db *gorm.DB, id uint) error { return db.Delete(&User{}, id).Error } func SoftDeleteUser(db *gorm.DB, id uint) error { return db.Delete(&User{}, id).Error }四、高级查询
4.1 条件查询
func AdvancedQuery(db *gorm.DB) ([]*User, error) { var users []*User // 复杂条件查询 err := db.Where("age >= ? AND active = ?", 18, true). Or("name LIKE ?", "%John%"). Not("email LIKE ?", "%@example.com"). Order("created_at DESC"). Limit(10). Offset(20). Find(&users).Error return users, err }4.2 原生SQL查询
func RawQuery(db *gorm.DB) ([]*User, error) { var users []*User err := db.Raw("SELECT * FROM users WHERE age > ?", 18).Scan(&users).Error return users, err } func RawQueryWithParams(db *gorm.DB, minAge, maxAge int) ([]map[string]interface{}, error) { var results []map[string]interface{} err := db.Raw( "SELECT name, COUNT(*) as count FROM users WHERE age BETWEEN ? AND ? GROUP BY name", minAge, maxAge, ).Scan(&results).Error return results, err }五、事务处理
func TransferMoney(db *gorm.DB, fromID, toID uint, amount float64) error { return db.Transaction(func(tx *gorm.DB) error { // 扣除余额 if err := tx.Model(&Account{}).Where("id = ?", fromID). Update("balance", gorm.Expr("balance - ?", amount)).Error; err != nil { return err } // 增加余额 if err := tx.Model(&Account{}).Where("id = ?", toID). Update("balance", gorm.Expr("balance + ?", amount)).Error; err != nil { return err } // 记录交易 if err := tx.Create(&Transaction{ FromID: fromID, ToID: toID, Amount: amount, }).Error; err != nil { return err } return nil }) }六、关联操作
6.1 一对多关系
func AddProductToCategory(db *gorm.DB, categoryID uint, product *Product) error { var category Category if err := db.First(&category, categoryID).Error; err != nil { return err } product.CategoryID = categoryID return db.Create(product).Error } func GetCategoryWithProducts(db *gorm.DB, categoryID uint) (*Category, error) { var category Category err := db.Preload("Products").First(&category, categoryID).Error return &category, err }6.2 多对多关系
type User struct { gorm.Model Roles []Role `gorm:"many2many:user_roles;"` } type Role struct { gorm.Model Name string Users []User `gorm:"many2many:user_roles;"` } func AssignRole(db *gorm.DB, userID, roleID uint) error { var user User if err := db.First(&user, userID).Error; err != nil { return err } var role Role if err := db.First(&role, roleID).Error; err != nil { return err } return db.Model(&user).Association("Roles").Append(&role) }七、迁移
7.1 自动迁移
func AutoMigrate(db *gorm.DB) error { return db.AutoMigrate( &User{}, &Product{}, &Category{}, &Order{}, &OrderItem{}, ) }7.2 手动迁移
func ManualMigration(db *gorm.DB) error { // 添加新字段 if err := db.Migrator().AddColumn(&User{}, "Phone"); err != nil { return err } // 修改字段类型 if err := db.Migrator().AlterColumn(&User{}, "Age"); err != nil { return err } // 创建索引 if err := db.Migrator().CreateIndex(&User{}, "idx_users_email"); err != nil { return err } return nil }八、性能优化
8.1 预编译语句
func UsePreparedStatement(db *gorm.DB) { db.Statement.Prepared = true }8.2 批量操作
func BatchInsert(db *gorm.DB, users []*User) error { return db.CreateInBatches(users, 100).Error }8.3 只读模式
func ReadOnlyTransaction(db *gorm.DB) error { return db.Transaction(func(tx *gorm.DB) error { tx.Statement.ForceSavePoint = true // 只读操作... return nil }) }结语
GORM提供了丰富的功能和优雅的API,极大地简化了Go语言中的数据库操作。通过合理使用关联、事务和迁移功能,可以构建高效、可维护的数据库应用。希望本文的实践经验能帮助你更好地使用GORM进行开发。
