Go语言ORM框架GORM深度解析
引言
GORM是Go语言中最流行的ORM(对象关系映射)框架,提供了强大的数据访问能力和优雅的API设计。本文将深入探讨GORM的核心功能、高级特性和最佳实践。
一、环境配置
1.1 安装GORM
go get gorm.io/gorm
go get gorm.io/driver/mysql
1.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进行开发。

373

被折叠的 条评论
为什么被折叠?



