Gorm 的基本使用

Gorm 基本使用

Gorm 是一个已经迭代了 10 多年的功能强大的 ORM 框架,被广泛使用并目拥有非常丰富的开源扩展。

官网:https://gorm.io/

Gorm 的安装

使用 go get 命令在项目中安装 gorm,其中数据库驱动根据实际情况安装,我这里安装的是 MySQL

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

Gorm 快速入门

下面是 Gorm 进行单表操作的简单用法,因为 golang 是强类型语言,需要用 model 来映射数据库表,可以通过 Gorm 的 AutoMigrate 函数生成数据库,也可以根据数据库建表语句反向生成 model,在线工具网址 http://sql2struct.atotoa.com/

  1. 创建 model
  2. 为 model 设置表名
  3. 利用 dsn 连接到数据库,获取连接
  4. 对数据库表进行操作
// 定义 gorm model
type Product struct {
    Code string
    Price uint
}

// 为 model 设置表名
func (p Product) TableName() string {
    return "product"
}

func main() {
    dsn := "username:root@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 {
		fmt.Printf("mysql connect error %v", err)
	}

    // 迁移 schema
  	db.AutoMigrate(&Product{})

    // create
    db.Create(&Product{Code:'D42',Price:100})

    // Read
    var product Product
    db.First(&product, 1) // 根据整型主键查找
    db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录

     // Update - 将 product 的 price 更新为 200
  	db.Model(&product).Update("Price", 200)
    
    // Update - 更新多个字段
    db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
    db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})

    // Delete - 删除 product
    db.Delete(&product, 1)
}

Gorm 创建数据

  1. 创建数据时处理冲突问题,使用 clause.OnConflict 处理冲突
p := &Product{Code:"D42",ID:1}
db.Clauses(clause.OnConflict{DoNothing:true}).Create(&p)
  1. 创建数据时使用默认值
type User struct {
    ID int64
    Name string `gorm:"default:user"`
    Age	int64	`gorm:default:18`
}

Gorm 查询数据

  1. 检索单个对象

GORM 提供了 First、Take、Last 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误

如果你想避免 ErrRecordNotFound 错误,你可以使用 Find,比如 db.Limit(1).Find(&user),Find 方法可以接受 struct 和 slice 的数据。

// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;

// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;

// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;

result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error        // returns error or nil

// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)
  1. 根据主键检索

如果主键是数字,则可以使用内联条件使用主键检索对象。使用字符串时需要格外小心,避免SQL 注入

db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;

db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;

db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);

当目标对象有一个主键值时,将使用主键构建查询条件

var user = User{ID: 10}
db.First(&user)
// SELECT * FROM users WHERE id = 10;

var result User
db.Model(User{ID: 10}).First(&result)
// SELECT * FROM users WHERE id = 10;
  1. 根据条件检索
  • String 条件
// Get first matched record
db.Where("name = ?", "user").First(&user)
// SELECT * FROM users WHERE name = 'user' ORDER BY id LIMIT 1;
  • Map 条件
// Map
db.Where(map[string]interface{}{"name": "user", "age": 20}).Find(&users)
// SELECT * FROM users WHERE name = "user" AND age = 20;
  • Not 条件,用法类似 where 条件
db.Not("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;
  • Or 条件
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
  • 排序条件
db.Order("age desc, name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;
  • Limit 和 offset 条件
db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;
  • Join 条件
db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})
// SELECT users.name, emails.email FROM `users` left join emails on emails.user_id = users.id

Gorm 更新数据

  1. 保存所有字段,Save 会保存所有的字段,即使字段是零值
db.Save(&user)
  1. 更新单个列
// User's ID is `111`:
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
  1. 更新多个列

使用 Struct 更新时,只会更新非零值,如果需要更新零值可以使用 Map 更新或使用 Select 选择字段:

// Update attributes with `struct`, will only update non-zero fields
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;

Gorm 删除

  1. 删除一条记录

删除一条记录时,删除对象需要指定主键,否则会触发 批量删除

// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;
  1. 批量删除
db.Where("email LIKE ?", "%jinzhu%").Delete(&Email{})
// DELETE from emails where email LIKE "%jinzhu%";

Gorm 原生 SQL

原生 SQL

db.Raw("SELECT id, name, age FROM users WHERE id = ?", 3).Scan(&result)

Gorm 事务

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

tx := db.begin()
// 这里执行对数据库的操作,应该用 tx 而不是 db
// 遇到错误时执行 tx.Rollback() 回滚 
tx.Commit()

Gorm提供了Tansaction方法用于自动提交事务,避免用户漏写Commit、Rollbcak.

db.Transaction(func(tx *gorm.DB) {
    // 这里执行操作逻辑
} )

Gorm Hook

GORM在提供了CURD的Hook能力。

Hook是在创建、查询、更新、删除等操作之前、之后自动调用的函数。

如果任何Hook返回错误,GORM将停止后续的操作并回滚事务。

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
    // 业务代码
}

func (u *User) AfterCreate(tx *gorm.DB) (err error) {
        // 业务代码
}

Gorm 性能提高

  • 对于写操作(创建、更新、删除),为了确保数据的完整性,GORM会将它们封装在事务内运行。但这会降低性能,你可以使用 SkipDefaultTransaction 关闭默认事务。
  • 使用 PrepareStmt 缓存预编译语句可以提高后续调用的速度
db, err := gorm.Open(dsn, &gorm.Config{
  SkipDefaultTransaction: true, // 关闭默认事务
    PrepareStmt:true // 缓存预编译语句
})

Gorm 生态

gorm 拥有非常丰富的扩展生态,以下是一部分常用生态

GORM 代码生成工具https://github.com/go-gorm/gen
GORM 分片库方案https://github.com/go-gorm/sharding
GORM 手动索引https://github.com/go-gorm/hints
GORM 乐观锁https://github.com/go-gorm/optimisticlock
GORM 读写分离https://github.com/go-gorm/dbresolver
GORM OpenTelemetry 扩展https://github.com/go-gorm/opentelemetry

引用

https://gorm.io/zh_CN/docs/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值