青训营X豆包MarsCode技术训练营|GORM(Go 的 ORM 库)连接数据库

39 阅读4分钟

GORM是什么?

GORM 是一个用于 Go 语言的 ORM(对象关系映射)库。它提供了一种简洁的方式来与数据库进行交互,使开发者能够通过 Go 语言的结构体来操作数据库中的数据,而不需要手动书写大量的 SQL 语句。GORM 支持常见的数据库系统,如 MySQL、PostgreSQL、SQLite 和 SQL Server 等,提供了丰富的功能,包括自动迁移、关联关系处理、预加载等,帮助开发者更高效地管理数据库操作。

GORM 的基本使用

  1. 安装 GORM

首先,你需要在你的 Go 项目中安装 GORM。可以使用 go get 命令:

bash

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql  # 如果你使用 MySQL
  1. 建立数据库连接

接下来,需要建立与数据库的连接:

package main

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

func main() {
    dsn := "username:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal(err)
    }

    // 进一步操作...
}
  1. 定义模型

定义一个数据模型,使用 Go 的结构体表示数据库表:

type User struct {
    gorm.Model  // 包含 ID, CreatedAt, UpdatedAt, DeletedAt 字段
    Name  string
    Email string
}
  1. 创建表

使用 GORM 自动迁移功能创建数据库表:

func main() {
    // ... 之前的数据库连接代码

    // 自动迁移
    db.AutoMigrate(&User{})
}
  1. 插入数据

往数据库表中插入数据:

func main() {
    // ... 之前的代码

    user := User{Name: "John Doe", Email: "john@example.com"}
    db.Create(&user)  // 插入新用户
}
  1. 查询数据

从数据库中查询数据:

func main() {
    // ... 之前的代码

    var user User
    db.First(&user, 1)  // 根据主键 ID 查询,找到 ID 为 1 的用户
    log.Println(user)
}
  1. 更新数据

更新现有的数据:

func main() {
    // ... 之前的代码

    var user User
    db.First(&user, 1)         // 查找用户
    user.Name = "Jane Doe"     // 修改名字
    db.Save(&user)             // 保存更改
}
  1. 删除数据

删除数据:

func main() {
    // ... 之前的代码

    var user User
    db.First(&user, 1)  // 查找用户
    db.Delete(&user)    // 删除用户
}

事务处理

在 GORM 中,事务处理是一个重要的功能,它允许你将多个数据库操作组合成一个原子操作。这意味着要么所有操作都成功执行(提交),要么如果其中一个操作失败,所有操作都不会生效(回滚)。这种特性在处理复杂业务逻辑或维护数据完整性时非常有用。在 GORM 中,使用 db.Transaction 方法来创建一个事务块。

func main() {
    // 建立数据库连接
    dsn := "username:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal(err)
    }

    // 开始事务
    err = db.Transaction(func(tx *gorm.DB) error {
        // 在这里执行数据库操作
        user := User{Name: "Transactional User", Email: "transactional@example.com"}
        if err := tx.Create(&user).Error; err != nil {
            return err // 返回错误时会回滚事务
        }

        article := Article{Title: "Transactional Article", UserID: user.ID}
        if err := tx.Create(&article).Error; err != nil {
            return err // 返回错误时会回滚事务
        }

        return nil // 没有错误则提交事务
    })

    if err != nil {
        log.Printf("事务失败: %v", err) // 处理事务失败
    } else {
        log.Println("事务成功")
    }
}

 事务的工作机制

  • 开始事务:当你调用 db.Transaction 时,GORM 会自动在数据库中开启一个事务。
  • 在事务块中执行操作:在传递给 Transaction 函数的闭包内,你可以使用 tx 对象(短期事务的 DB 连接)执行数据库操作。
  • 错误处理与回滚:如果在事务块中发生了错误(通过返回错误),GORM 会自动回滚事务,确保没有任何操作被提交。
  • 提交事务:如果没有发生错误,事务块正常结束,GORM 将提交所有修改。

GORM 支持事务嵌套,但请注意,嵌套事务实际上是通过“保存点”(savepoints)实现的。这意味着,如果外部事务被回滚,内部事务也会被回滚,而如果内部事务出现错误,不会影响外部事务的提交。

err = db.Transaction(func(tx *gorm.DB) error {
    // 执行一些操作
    err := tx.Create(&user).Error
    if err != nil {
        return err
    }

    // 嵌套事务
    err = tx.Transaction(func(tx2 *gorm.DB) error {
        // 在嵌套事务中执行操作
        err := tx2.Create(&article).Error
        if err != nil {
            return err // 内部错误将导致回滚
        }
        return nil
    })

    // 如果内部事务出错外部事务将被回滚
    if err != nil {
        return err
    }

    return nil // 如果外部没有错误则提交
})

使用场景

事务处理在一些特定场景下非常重要,例如:

  • 转账操作:在金融系统中,转账操作必须确保扣除金额和增加金额同时成功。
  • 批量创建:在创建与某个实体相关的多个记录时,确保要么全都成功,要么都不存储。
  • 用户注册:在用户注册时,同时存储用户信息和用户角色(或权限)时,可以使用事务保护数据一致性。

事务中检测错误后应及时返回错误,以保证事务能够回滚。事务的持续时间应尽量缩短,避免长时间占用数据库连接。在嵌套事务中,尽量避免过多的嵌套层级,保持代码简洁可读。