Go语言使用gorm操作数据库

Go语言使用gorm操作数据库

介绍

在用 Go 开发项目时,我们免不了要和数据库打交道。目前,GitHub 上 star 数最多的是 GORM,它也是当前 Go 项目中使用最多的 ORM。

GORM 是 Go 语言的 ORM 包,功能强大,调用方便。像腾讯、华为、阿里这样的大厂,都在使用 GORM 来构建企业级的应用。GORM 有很多特性,开发中常用的核心特性如下:功能全。使用 ORM 操作数据库的接口,GORM 都有,可以满足我们开发中对数据库调用的各类需求。支持钩子方法。这些钩子方法可以应用在 Create、Save、Update、Delete、Find 方法中。开发者友好,调用方便。支持 Auto Migration。支持关联查询。支持多种关系数据库,例如 MySQL、Postgres、SQLite、SQLServer 等。

在企业级 Go 项目开发中,使用 GORM 库主要用来完成以下数据库操作:

连接和关闭数据库。连接数据库时,可能需要设置一些参数,比如最大连接数、最大空闲连接数、最大连接时长等。

插入表记录。可以插入一条记录,也可以批量插入记录。

更新表记录。可以更新某一个字段,也可以更新多个字段。

查看表记录。可以查看某一条记录,也可以查看符合条件的记录列表。

删除表记录。可以删除某一个记录,也可以批量删除。删除还支持永久删除和软删除。

在一些小型项目中,还会用到 GORM 的表结构自动迁移功能。

安装

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

不同的数据库安装不同的驱动即可。

连接

设置连接地址信息
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" 
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   "",
			SingularTable: true, //使用单数表名,启用该选项后,`User`表将是 `user`
			NameReplacer:  nil,
			NoLowerCase:   false,
		},
	})

如果需要 GORM 正确地处理 time.Time 类型,在连接数据库时需要带上 parseTime 参数。如果要支持完整的 UTF-8 编码,可将charset=utf8更改为charset=utf8mb4。

GORM 支持连接池,底层是用 database/sql 包来维护连接池的,连接池设置如下:

  sqlDB, err := db.DB()
	sqlDB.SetMaxOpenConns(100)                 //最大连接数
	sqlDB.SetMaxIdleConns(100)                 //最大空闲连接数
	sqlDB.SetConnMaxLifetime(10 * time.Second) //空闲连接最多存活时间

自动迁移表结构

type User struct {
	gorm.Model
	Name string `gorm:"column: name"`
	Age  int  `gorm: "column: age"`
	Birthday time.Time `gorm:"column: birthday"`
}
//实现TableName方法可以修改表名
func (u *User) TableName() string {
	return "user"
}

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

操作

创建记录
user := User{
		Name:     "kuludi",
		Age:      20,
		Birthday: time.Now(),
	}

	result := db.Create(&user) //通过数据的指针来创建

db.Create 函数会返回如下 3 个值:

user.ID:返回插入数据的主键,这个是直接赋值给 user 变量。

result.Error:返回 error。

result.RowsAffected:返回插入记录的条数。

当需要插入的数据量比较大时,可以批量插入,以提高插入性能:

  var users = []User{{Name: "red1"}, {Name: "red2"}, {Name: "red3"}}
	db.Create(&users)
	for _, user := range users {
		fmt.Println(user.ID, user.Name) // 1 red1 2 red2 3 red3
	}
删除记录

我们可以通过 Delete 方法删除记录:

  //delete from user where name = "red1"
	db.Where("name = ?", "red1").Delete(&User{})

GORM 也支持根据主键进行删除,例如:

  //delete from user where id = 1;
	db.Delete(&User{}, 1)

不过,我更喜欢使用 db.Where 的方式进行删除,这种方式有两个优点。

第一个优点是删除方式更通用。使用 db.Where 不仅可以根据主键删除,还能够随意组合条件进行删除。

第二个优点是删除方式更显式,这意味着更易读。如果使用db.Delete(&User{}, 10),你还需要确认 User 的主键,如果记错了主键,还可能会引入 Bug。

此外,GORM 也支持批量删除:

db.Where("name in (?)", []string{"red2", "red3"}).Delete(&User{})
两种删除方式
  1. 软删除

软删除是指执行 Delete 时,记录不会被从数据库中真正删除。GORM 会将 DeletedAt 设置为当前时间,并且不能通过正常的方式查询到该记录。如果模型包含了一个 gorm.DeletedAt 字段,GORM 在执行删除操作时,会软删除该记录。上面的删除方法就是一个软删除。

可以看到,GORM 并没有真正把记录从数据库删除掉,而是只更新了 deleted_at 字段。在查询时,GORM 查询条件中新增了AND deleted_at IS NULL条件,所以这些被设置过 deleted_at 字段的记录不会被查询到。对于一些比较重要的数据,我们可以通过软删除的方式删除记录,软删除可以使这些重要的数据后期能够被恢复,并且便于以后的排障。

我们可以通过下面的方式查找被软删除的记录:

db.Unscoped().Where("name = ?", "red1").Find(&User{})
  1. 永久删除

如果想永久删除一条记录,可以使用 Unscoped:

db.Unscoped().Delete(&User{})
更新记录

GORM 中,最常用的更新方法如下:

    db.First(&user)
	user.Name = "hu"
	user.Age = 300
	db.Save(&user)

上述方法会保留所有字段,所以执行 Save 时,需要先执行 First,获取某个记录的所有列的值,然后再对需要更新的字段设置值。

还可以指定更新单个列:

db.Model(&User{}).Where("name = ?","hu").Update("age",500)

也可以指定更新多个列:

db.Model(&User{}).Where("name = ?", "hu").Updates(User{Name: "hong", Age: 888, Birthday: time.Now()})

这里要注意,这个方法只会更新非零值的字段。

查询记录

GORM 支持不同的查询方法,下面我来讲解三种在开发中经常用到的查询方式,分别是检索单个记录、查询所有符合条件的记录和智能选择字段。

  1. 检索单个记录

下面是检索单个记录的示例代码:


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

// 获取最后一条记录(主键降序)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
db.Last(&user)
result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error        // returns error

// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)

如果 model 类型没有定义主键,则按第一个字段排序。

  1. 查询所有符合条件的记录

示例代码如下:


users := make([]*User, 0)

// SELECT * FROM users WHERE name <> 'red';
db.Where("name <> ?", "red").Find(&users)
  1. 智能选择字段

你可以通过 Select 方法,选择特定的字段。我们可以定义一个较小的结构体来接受选定的字段:


type APIUser struct {
  ID   uint
  Name string
}

// SELECT `id`, `name` FROM `users` LIMIT 10;
db.Model(&User{}).Limit(10).Find(&APIUser{})

除了上面讲的三种常用的基本查询方法,GORM 还支持高级查询,下面我来介绍下。

高级查询

GORM 支持很多高级查询功能,这里我主要介绍 4 种。

  1. 指定检索记录时的排序方式

示例代码如下:

// SELECT * FROM users ORDER BY age desc, name;
db.Order("age desc, name").Find(&users)
  1. Limit & Offset

Offset 指定从第几条记录开始查询,

Limit 指定返回的最大记录数。Offset 和 Limit 值为 -1 时,消除 Offset 和 Limit 条件。

另外,Limit 和 Offset 位置不同,效果也不同。

// SELECT * FROM users OFFSET 5 LIMIT 10;
db.Limit(10).Offset(5).Find(&users)
  1. Distinct

Distinct 可以从数据库记录中选择不同的值。

db.Distinct("name", "age").Order("name, age desc").Find(&results)
  1. Count

Count 可以获取匹配的条数。


var count int64
// SELECT count(1) FROM users WHERE name = 'red'; (count)
db.Model(&User{}).Where("name = ?", "red").Count(&count)

GORM 还支持很多高级查询功能,比如内联条件、Not 条件、Or 条件、Group & Having、Joins、Group、FirstOrInit、FirstOrCreate、迭代、FindInBatches 等。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值