跳过正文

GORM 入门教程:数据库连接与基础 CRUD 操作

·648 字·4 分钟· loading · loading ·
lixxix
作者
lixxix
关注科技,编程改变生活!
GORM 是 Go 语言中最流行的 ORM(对象关系映射)框架,它提供了简洁易用的 API,让我们能够用 Go 结构体来操作数据库。本文将详细介绍 GORM 的基础用法。

环境准备
#

首先,你需要安装 GORM:

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
提示

本文使用 SQLite 作为演示数据库,因为它无需额外安装即可运行。生产环境请使用 MySQL 或 PostgreSQL。


1. 数据库连接
#

1.1 基础连接
#

package main

import (
    "log"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

func main() {
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        log.Fatal("数据库连接失败:", err)
    }
    log.Println("数据库连接成功!")
}

1.2 连接 MySQL
#

dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

1.3 连接 PostgreSQL
#

dsn := "host=user user=password dbname=dbname port=5432 sslmode=disable TimeZone=Asia/Shanghai"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

2. 定义模型
#

GORM 使用 Go 结构体来定义数据库表模型:

type User struct {
    ID           uint      `gorm:"primaryKey"`           // 主键
    Name         string    `gorm:"size:255;not null"`   // 姓名
    Email        string    `gorm:"uniqueIndex;size:255"` // 邮箱(唯一索引)
    Age          int       `gorm:"not null"`             // 年龄
    Birthday     *time.Time                                // 生日(指针类型可为空
    CreatedAt    time.Time                                // 创建时间
    UpdatedAt    time.Time                                // 更新时间
}

常用标签说明
#

标签说明
primaryKey设为主键
autoIncrement自增
size:n字段大小
not null非空约束
uniqueIndex唯一索引
index普通索引
default:value默认值
foreignKey外键

3. AutoMigrate 自动迁移
#

AutoMigrate 可以自动创建或更新数据库表结构:

// 自动迁移(创建表、添加新字段、删除旧字段)
db.AutoMigrate(&User{})

// 迁移指定表
db.Migrator().CreateTable(&User{})

// 检查表是否存在
db.Migrator().HasTable(&User{})
警告

生产环境中谨慎使用 AutoMigrate,它可能会导致数据丢失。建议使用 Migration 文件来管理数据库变更。


4. 增删改查(CRUD)
#

4.1 创建记录(Create)
#

// 创建单条记录
user := User{Name: "张三", Email: "zhangsan@example.com", Age: 25}
result := db.Create(&user)

fmt.Printf("插入的ID: %d\n", user.ID)
fmt.Printf("影响的行数: %d\n", result.RowsAffected)

// 创建记录并返回错误
if err := db.Create(&user).Error; err != nil {
    log.Fatal(err)
}
// 批量创建
users := []User{
    {Name: "李四", Email: "lisi@example.com", Age: 30},
    {Name: "王五", Email: "wangwu@example.com", Age: 28},
    {Name: "赵六", Email: "zhaoliu@example.com", Age: 35},
}
db.Create(&users)

4.2 查询记录(Read)
#

// 根据主键查询
var user User
db.First(&user, 1) // 查询 ID 为 1 的记录

// 条件查询
var user User
db.Where("name = ?", "张三").First(&user)

// 多个条件
db.Where("age > ? AND name LIKE ?", 20, "%张%").Find(&users)

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

// 查询所有记录
var allUsers []User
db.Find(&allUsers)

// 只查询指定字段
db.Select("name, email").Find(&users)

// 排序
db.Order("age DESC, created_at DESC").Find(&users)

// 限制数量
db.Limit(10).Offset(5).Find(&users) // 跳过前5条,取10条

4.3 更新记录(Update)
#

// 更新单字段
db.Model(&user).Update("name", "新名字")

// 更新多个字段
db.Model(&user).Updates(User{Name: "新名字", Age: 26})

// 使用 Where 更新
db.Where("name = ?", "张三").Model(&User{}).Update("age", 30)

// 更新所有记录
db.Model(&User{}).Where("age < ?", 18).Update("status", "未成年")

4.4 删除记录(Delete)
#

// 删除单条记录
db.Delete(&user, 1) // 删除 ID 为 1 的记录

// 根据条件删除
db.Where("age < ?", 18).Delete(&User{})

// 软删除(需要包含 DeletedAt 字段)
// db.Delete(&user) // 实际上是将 DeletedAt 设置为当前时间

// 永久删除
db.Unscoped().Delete(&user)

5. 完整示例
#

以下是一个完整的 CRUD 操作示例:

package main

import (
    "fmt"
    "log"
    "time"

    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

type User struct {
    ID        uint      `gorm:"primaryKey"`
    Name      string    `gorm:"size:100;not null"`
    Email     string    `gorm:"uniqueIndex;size:100"`
    Age       int       `gorm:"not null"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

// TableName 自定义表名(可选)
func (User) TableName() string {
    return "users"
}

func main() {
    // 连接数据库
    db, err := gorm.Open(sqlite.Open("demo.db"), &gorm.Config{})
    if err != nil {
        log.Fatal(err)
    }

    // 自动迁移
    db.AutoMigrate(&User{})

    // ====== Create - 创建 ======
    user := User{Name: "张三", Email: "zhangsan@example.com", Age: 25}
    db.Create(&user)
    fmt.Printf("创建用户,ID: %d\n", user.ID)

    // ====== Read - 读取 ======
    var foundUser User
    db.First(&foundUser, user.ID)
    fmt.Printf("查询用户: %s, %s, %d岁\n", foundUser.Name, foundUser.Email, foundUser.Age)

    // 条件查询
    var users []User
    db.Where("age > ?", 20).Find(&users)
    fmt.Printf("年龄大于20岁的用户: %d 人\n", len(users))

    // ====== Update - 更新 ======
    db.Model(&foundUser).Update("age", 26)
    fmt.Printf("更新后的年龄: %d\n", foundUser.Age)

    // ====== Delete - 删除 ======
    db.Delete(&foundUser)
    fmt.Println("用户已删除")
}

6. 高级查询技巧
#

6.1 链式调用
#

// 链式调用示例
db.Where("name LIKE ?", "%张%").
    Where("age >= ?", 20).
    Order("created_at DESC").
    Limit(10).
    Find(&users)

6.2 Scopes 复用查询条件
#

func PopularUsers(db *gorm.DB) *gorm.DB {
    return db.Where("age > ?", 20).Order("age DESC")
}

func RecentlyRegistered(db *gorm.DB) *gorm.DB {
    return db.Where("created_at > ?", time.Now().AddDate(0, -1, 0))
}

// 使用 Scope
db.Scopes(PopularUsers, RecentlyRegistered).Find(&users)

6.3 事务操作
#

func TransferMoney(db *gorm.DB) 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
        }

        return nil
    })
}

总结
#

本文介绍了 GORM 的核心功能:

  1. 数据库连接 - 支持 SQLite、MySQL、PostgreSQL 等多种数据库
  2. 模型定义 - 使用 Go 结构体 + 标签定义数据库表结构
  3. AutoMigrate - 自动迁移数据库表结构
  4. CRUD 操作 - 完整的创建、读取、更新、删除 API
  5. 高级特性 - 链式调用、Scopes、事务等
提示

建议查看 GORM 官方文档 获取更详细的信息和高级用法。