青训营X豆包MarsCode Gorm框架我的粗浅理解 | 豆包MarsCode AI 刷题

118 阅读3分钟

定义

Gorm 是一个功能强大的 Go ORM 框架,是链式调用的

操作语法

创建一个数据库的连接

Gorm是使用dns来进行连接的

var db *gorm.DB

func Init() error {
	var err error
	dsn := "root:123456@tcp(127.0.0.1:3306)/gowebtry?charset=utf8mb4&parseTime=True&loc=Local"
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	return err
}

增删改查

db 对象的方法与数据库的常见操作(UPDATEDELETESELECTINSERT)是一一对应的

db.Clauses

在 Gorm 中,db.Clauses 并不直接对应传统的 SQL 操作(INSERTSELECTUPDATEDELETE),而是一个功能性扩展,用于在这些操作中动态添加或修改 SQL 子句(Clause)

db.Clauses(clause.Limit{Limit: 10}).Find(&users)

在查询中添加 LIMIT 10 子句,限制查询结果为 10 条。

用clause.OnConflict处理数据冲突

clause.OnConflict 支持指定冲突字段、更新字段、忽略操作等,满足各种场景需求:

  • 插入时忽略冲突。
  • 冲突时更新指定字段。
  • 自定义冲突处理逻辑。 比如这样
db.Clauses(clause.OnConflict{
    Columns:   []clause.Column{{Name: "id"}}, // 指定冲突字段
    DoUpdates: clause.AssignmentColumns([]string{"name", "age"}), // 冲突时更新的字段
}).Create(&User{ID: 1, Name: "Bob", Age: 30})
  • 如果 ID = 1 不存在,插入记录 {ID: 1, Name: "Bob", Age: 30}
  • 如果 ID = 1 已存在,则更新其 nameage 字段。

使用的小坑

First的使用踩坑

使用 First时,需要注意查询不到数据会返回ErrRecordNotFound.使用 Find 查询多条数据,查询不到数据不会返回错误。

使用结构体作为查询条件

当使用结构作为条件查询时,GORM只会查询非零值字段,因为0还有无效值的含义,GORM无法分辨究竟是0还是无效值的意思,所以就直接选择忽略了,如果我们的字段是0或者false或者其他零值,该字段不会被用来构建查询条件,如果要用的话用Map来构建

软删除

GORM 默认通过一个名为 gorm.DeletedAt 的字段实现软删除。当该字段值为 NULL 时,表示记录有效;当它被赋值为时间戳时,表示记录已被删除

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

通过调用 GORM 的 Delete 方法删除记录时,GORM 不会真正执行 DELETE SQL,而是更新 DeletedAt 字段为当前时间。

db.Delete(&user)

之后查询的时候会排除DeletedAt不是空的数据,从而实现软删的 效果

可以通过更新 DeletedAt 字段为 NULL 恢复软删除记录

db.Model(&user).Update("DeletedAt", nil)

事务

Gorm 提供了Begin、Commit、Rollback方法用于使用事务

(事务是用来确保一组数据库操作要么全部成功,要么全部失败的机制。通过使用事务,能够保证数据一致性,尤其是在多个表之间存在复杂关联操作时)

Tansaction避免漏写Commit、Rollbcak

db.Transaction(func(tx *gorm.DB) error {
    // 在这里写所有的事务操作
    // 使用 tx 而不是 db 并且tx := db.Begin()
    if err := tx.Create(&Order{UserID: 1, TotalAmount: 100}).Error; err != nil {
        return err // 返回错误会触发回滚
    }

    if err := tx.Model(&Product{}).Where("id = ?", 1).Update("stock", gorm.Expr("stock - ?", 1)).Error; err != nil {
        return err // 返回错误会触发回滚
    }

    return nil // 返回 nil 会触发提交事务
})

Hook回调函数

回调函数允许你在执行数据库操作时插入自定义逻辑,比如数据验证、默认值填充、日志记录等。

Hook 提供了一种机制,让开发者可以在事件的前后添加自定义逻辑:

  • 数据操作前:在执行操作前修改或验证数据。
  • 数据操作后:在操作完成后触发逻辑,例如清理、日志记录或通知。

Gorm性能提高

对于写操作(创建、更新、删除),为了确保数据的完整性,GORM会将它们封装在事务内运行。但这会降低性能,你可以使用 SkipDefaultTransaction关闭默认事务。

使用 PrepareStmt 缓存预编译语句可以提高后续调用的速度,本机测试提高大约 35 %左右。