GORM集成 #

一、GORM安装 #

1.1 安装GORM #

bash
go get gorm.io/gorm
go get gorm.io/driver/mysql

1.2 其他数据库驱动 #

bash
go get gorm.io/driver/postgres
go get gorm.io/driver/sqlite
go get gorm.io/driver/sqlserver

二、数据库连接 #

2.1 MySQL连接 #

go
package main

import (
    "fmt"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

var db *gorm.DB

func initDB() error {
    dsn := "root:password@tcp(localhost:3306)/myapp?charset=utf8mb4&parseTime=True&loc=Local"
    
    var err error
    db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        return err
    }
    
    sqlDB, err := db.DB()
    if err != nil {
        return err
    }
    
    sqlDB.SetMaxOpenConns(25)
    sqlDB.SetMaxIdleConns(5)
    sqlDB.SetConnMaxLifetime(5 * time.Minute)
    
    return nil
}

2.2 SQLite连接 #

go
db, err := gorm.Open(sqlite.Open("myapp.db"), &gorm.Config{})

2.3 PostgreSQL连接 #

go
dsn := "host=localhost user=postgres password=password dbname=myapp port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

三、模型定义 #

3.1 基本模型 #

go
type User struct {
    ID        uint           `gorm:"primaryKey" json:"id"`
    Name      string         `gorm:"size:100;not null" json:"name"`
    Email     string         `gorm:"size:100;uniqueIndex;not null" json:"email"`
    Password  string         `gorm:"size:255;not null" json:"-"`
    Age       int            `gorm:"default:0" json:"age"`
    Status    string         `gorm:"size:20;default:'active'" json:"status"`
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}

3.2 模型标签 #

标签 说明
primaryKey 主键
uniqueIndex 唯一索引
index 普通索引
size 字段长度
not null 非空
default 默认值
unique 唯一
comment 注释
autoIncrement 自增

3.3 关联模型 #

go
type User struct {
    ID      uint      `gorm:"primaryKey" json:"id"`
    Name    string    `json:"name"`
    Posts   []Post    `gorm:"foreignKey:UserID" json:"posts"`
    Profile Profile   `gorm:"foreignKey:UserID" json:"profile"`
}

type Post struct {
    ID     uint   `gorm:"primaryKey" json:"id"`
    Title  string `json:"title"`
    Body   string `json:"body"`
    UserID uint   `json:"user_id"`
    User   User   `json:"user"`
}

type Profile struct {
    ID     uint   `gorm:"primaryKey" json:"id"`
    Bio    string `json:"bio"`
    UserID uint   `json:"user_id"`
}

四、自动迁移 #

4.1 迁移模型 #

go
func main() {
    initDB()
    
    db.AutoMigrate(
        &User{},
        &Post{},
        &Profile{},
    )
}

4.2 检查表是否存在 #

go
if db.Migrator().HasTable(&User{}) {
    fmt.Println("Users table exists")
}

4.3 创建表 #

go
db.Migrator().CreateTable(&User{})

4.4 删除表 #

go
db.Migrator().DropTable(&User{})

五、CRUD操作 #

5.1 创建 #

go
user := User{
    Name:     "张三",
    Email:    "zhangsan@example.com",
    Password: "hashed_password",
    Age:      25,
}

result := db.Create(&user)
if result.Error != nil {
    return result.Error
}

fmt.Println(user.ID)

5.2 批量创建 #

go
users := []User{
    {Name: "张三", Email: "zhangsan@example.com"},
    {Name: "李四", Email: "lisi@example.com"},
}

db.Create(&users)

5.3 查询单条 #

go
var user User

db.First(&user, 1)

db.First(&user, "email = ?", "zhangsan@example.com")

db.Where("name = ?", "张三").First(&user)

5.4 查询多条 #

go
var users []User

db.Find(&users)

db.Where("age > ?", 20).Find(&users)

db.Where("name LIKE ?", "%张%").Find(&users)

db.Order("created_at desc").Find(&users)

db.Limit(10).Offset(0).Find(&users)

5.5 分页查询 #

go
func getUsers(page, size int) ([]User, int64) {
    var users []User
    var total int64
    
    db.Model(&User{}).Count(&total)
    
    offset := (page - 1) * size
    db.Offset(offset).Limit(size).Find(&users)
    
    return users, total
}

5.6 更新 #

go
db.Model(&user).Update("name", "李四")

db.Model(&user).Updates(User{Name: "李四", Age: 30})

db.Model(&user).Updates(map[string]interface{}{
    "name": "王五",
    "age":  28,
})

db.Model(&User{}).Where("status = ?", "inactive").Update("status", "active")

5.7 删除 #

go
db.Delete(&user)

db.Delete(&User{}, 1)

db.Where("name = ?", "张三").Delete(&User{})

5.8 软删除 #

go
type User struct {
    ID        uint           `gorm:"primaryKey"`
    Name      string
    DeletedAt gorm.DeletedAt `gorm:"index"`
}

db.Delete(&user)

db.Unscoped().Find(&users)

六、查询条件 #

6.1 Where条件 #

go
db.Where("name = ?", "张三").First(&user)

db.Where("name <> ?", "张三").Find(&users)

db.Where("age > ?", 20).Find(&users)

db.Where("age BETWEEN ? AND ?", 20, 30).Find(&users)

db.Where("name IN ?", []string{"张三", "李四"}).Find(&users)

db.Where("name LIKE ?", "%张%").Find(&users)

db.Where("name = ? AND age > ?", "张三", 20).Find(&users)

6.2 Or条件 #

go
db.Where("name = ?", "张三").Or("name = ?", "李四").Find(&users)

6.3 Not条件 #

go
db.Not("name = ?", "张三").Find(&users)

6.4 In条件 #

go
db.Where("id IN ?", []int{1, 2, 3}).Find(&users)

6.5 排序 #

go
db.Order("age desc").Find(&users)

db.Order("age desc, name asc").Find(&users)

6.6 分组 #

go
type Result struct {
    Status string
    Count  int
}

var results []Result
db.Model(&User{}).Select("status, count(*) as count").Group("status").Find(&results)

七、关联查询 #

7.1 预加载 #

go
db.Preload("Posts").Find(&users)

db.Preload("Posts").Preload("Profile").Find(&users)

db.Preload("Posts", "status = ?", "published").Find(&users)

7.2 关联创建 #

go
user := User{
    Name: "张三",
    Posts: []Post{
        {Title: "文章1", Body: "内容1"},
        {Title: "文章2", Body: "内容2"},
    },
}

db.Create(&user)

7.3 关联查询 #

go
var user User
db.First(&user, 1)

var posts []Post
db.Model(&user).Association("Posts").Find(&posts)

八、事务 #

8.1 自动事务 #

go
err := db.Transaction(func(tx *gorm.DB) error {
    if err := tx.Create(&User{Name: "张三"}).Error; err != nil {
        return err
    }
    
    if err := tx.Create(&Post{Title: "文章"}).Error; err != nil {
        return err
    }
    
    return nil
})

8.2 手动事务 #

go
tx := db.Begin()

defer func() {
    if r := recover(); r != nil {
        tx.Rollback()
    }
}()

if err := tx.Create(&User{Name: "张三"}).Error; err != nil {
    tx.Rollback()
    return err
}

if err := tx.Create(&Post{Title: "文章"}).Error; err != nil {
    tx.Rollback()
    return err
}

tx.Commit()

九、完整示例 #

go
package main

import (
    "fmt"
    "net/http"
    "time"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "github.com/labstack/echo/v4"
)

type User struct {
    ID        uint           `gorm:"primaryKey" json:"id"`
    Name      string         `gorm:"size:100;not null" json:"name"`
    Email     string         `gorm:"size:100;uniqueIndex;not null" json:"email"`
    Age       int            `gorm:"default:0" json:"age"`
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}

type Post struct {
    ID        uint           `gorm:"primaryKey" json:"id"`
    Title     string         `gorm:"size:200;not null" json:"title"`
    Body      string         `json:"body"`
    UserID    uint           `json:"user_id"`
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
}

var db *gorm.DB

func initDB() error {
    dsn := "root:password@tcp(localhost:3306)/myapp?charset=utf8mb4&parseTime=True&loc=Local"
    
    var err error
    db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        return err
    }
    
    db.AutoMigrate(&User{}, &Post{})
    
    return nil
}

func main() {
    if err := initDB(); err != nil {
        panic(err)
    }
    
    e := echo.New()
    
    e.GET("/users", listUsers)
    e.GET("/users/:id", getUser)
    e.POST("/users", createUser)
    e.PUT("/users/:id", updateUser)
    e.DELETE("/users/:id", deleteUser)
    
    e.Logger.Fatal(e.Start(":8080"))
}

func listUsers(c echo.Context) error {
    page := 1
    size := 10
    
    var users []User
    var total int64
    
    db.Model(&User{}).Count(&total)
    
    offset := (page - 1) * size
    db.Offset(offset).Limit(size).Find(&users)
    
    return c.JSON(http.StatusOK, map[string]interface{}{
        "data":  users,
        "total": total,
        "page":  page,
        "size":  size,
    })
}

func getUser(c echo.Context) error {
    id := c.Param("id")
    
    var user User
    if err := db.First(&user, id).Error; err != nil {
        return echo.NewHTTPError(http.StatusNotFound, "用户不存在")
    }
    
    return c.JSON(http.StatusOK, user)
}

func createUser(c echo.Context) error {
    user := new(User)
    if err := c.Bind(user); err != nil {
        return err
    }
    
    if err := db.Create(user).Error; err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, err.Error())
    }
    
    return c.JSON(http.StatusCreated, user)
}

func updateUser(c echo.Context) error {
    id := c.Param("id")
    
    var user User
    if err := db.First(&user, id).Error; err != nil {
        return echo.NewHTTPError(http.StatusNotFound, "用户不存在")
    }
    
    if err := c.Bind(&user); err != nil {
        return err
    }
    
    db.Save(&user)
    
    return c.JSON(http.StatusOK, user)
}

func deleteUser(c echo.Context) error {
    id := c.Param("id")
    
    if err := db.Delete(&User{}, id).Error; err != nil {
        return echo.NewHTTPError(http.StatusNotFound, "用户不存在")
    }
    
    return c.NoContent(http.StatusNoContent)
}

十、总结 #

GORM集成要点:

要点 说明
连接 gorm.Open()
模型 struct定义
迁移 AutoMigrate()
创建 Create()
查询 First()、Find()
更新 Update()、Updates()
删除 Delete()
事务 Transaction()

准备好学习Redis集成了吗?让我们进入下一章!

最后更新:2026-03-28