database/sql and gorm | 青训营笔记

334 阅读7分钟

database/sql and gorm| 青训营笔记

理解 database/sql

Go语言中与数据库交互的库database/sql。这个库提供了一种通用的接口,可以与各种关系型数据库进行交互,如MySQL、PostgreSQL等。

  1. 数据库连接与连接池:
    • 在使用database/sql与数据库进行交互时,我们首先需要建立数据库连接。连接池是一种维护和管理数据库连接的机制,它可以有效地重复使用连接,减少每次连接的开销。使用连接池可以提高数据库访问的性能和效率。
    • 连接池的大小需要根据应用的需求进行合理的配置。连接池过小可能导致连接不够用,而连接池过大则可能造成资源浪费。通过监控和调整连接池的大小,可以优化应用程序的数据库访问性能。
  2. SQL语句执行:
    • 在使用database/sql执行SQL语句时,我们需要注意SQL注入的问题。为了避免SQL注入攻击,我们应该使用参数化查询(Prepared Statements)或者使用ORM库(如GORM)来进行数据的绑定,而不是直接拼接SQL语句。
    • 另外,使用事务(Transaction)可以确保一组SQL语句要么全部执行成功,要么全部回滚。事务的使用可以保证数据的一致性和完整性。
  3. 数据库错误处理:
    • 在与数据库交互的过程中,可能会出现各种错误,如连接错误、查询错误等。对于这些错误,我们应该进行适当的处理和错误恢复,以保证应用程序的稳定性和可靠性。
    • 错误处理的方式可以是日志记录、错误返回或者进行适当的重试。我们需要根据具体的业务场景和需求来选择合适的错误处理策略。

GORM的使用

快速开始:

package main

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

type Product struct {
  gorm.Model
  Code  string
  Price uint
}

func main() {
  db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
  if err != nil {
    panic("failed to connect database")
  }

  // 迁移 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是一个强大的Go语言的ORM库,它提供了方便的接口和工具,简化了与数据库的交互过程。以下是我对Gorm的一些个人思考和使用经验:

  1. 模型定义与映射:
    • 在使用GORM时,我们需要定义数据库表与Go结构体之间的映射关系。通过GORM的标签(Tag)机制,我们可以方便地指定字段的名称、类型、约束等信息,从而实现对象与数据库表的映射。
    • 此外,GORM还支持模型之间的关联关系,如一对一、一对多、多对多等。通过合理定义模型之间的关系,可以简化复杂查询和操作的编
    • 写,提高代码的可读性和开发效率。
  2. 查询和操作数据:
    • GORM提供了丰富的查询和操作数据的方法,如创建、读取、更新和删除(CRUD)等。通过链式调用这些方法,我们可以方便地构建复杂的查询条件和操作逻辑。
    • 使用GORM的预加载(Preload)功能可以优化查询性能,避免N+1查询的问题。预加载可以在查询相关联的数据时,一次性将所有数据加载到内存中,减少数据库查询的次数,提高性能。
    • 另外,GORM还支持原生SQL查询和执行,这在某些复杂的查询场景下非常有用。我们可以直接编写SQL语句,并使用GORM的API将查询结果映射到Go结构体中。

GORM 设计原理

image-20230520091244096转存失败,建议直接上传图片文件

  1. 链式调用和方法组合:
    • GORM的设计采用了链式调用的方式,通过不断追加方法来构建查询和操作的过程。这种设计使得代码的可读性和可维护性得到提高,同时也方便了方法的组合和复用。
    • 通过方法组合,我们可以将一系列的查询条件和操作逻辑封装成一个可复用的方法。这样,我们可以在不同的地方重复使用这些方法,提高代码的效率和一致性。
  2. 回调(Callback)机制:
    • GORM的回调机制可以在模型的生命周期中插入自定义的逻辑。例如,在创建记录之前或之后执行某些操作,或者在更新记录之前验证数据的有效性等。
    • 这种回调机制使得我们可以在不改动GORM源码的情况下,扩展或修改GORM的行为。通过定义回调函数,并注册到合适的事件上,我们可以实现自定义的业务逻辑。

image-20230520091322403转存失败,建议直接上传图片文件

GORM 最佳实践

CURD:

package main

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

// User 结构体表示数据库中的用户表
type User struct {
	ID    uint   `gorm:"primaryKey"`
	Name  string `gorm:"size:255"`
	Age   int
	Email string `gorm:"size:255"`
}

func main() {
	dsn := "user:password@tcp(localhost:3306)/database_name?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("无法连接到数据库")
	}

	// 自动迁移数据库结构
	err = db.AutoMigrate(&User{})
	if err != nil {
		panic("数据库迁移失败")
	}

	// 创建操作
	user := User{Name: "John", Age: 30, Email: "john@example.com"}
	result := db.Create(&user)
	if result.Error != nil {
		panic("创建用户失败")
	}

	// 读取操作
	var users []User
	result = db.Find(&users)
	if result.Error != nil {
		panic("查询用户失败")
	}
	fmt.Println("所有用户:", users)

	// 更新操作
	user.Age = 35
	result = db.Save(&user)
	if result.Error != nil {
		panic("更新用户失败")
	}

	// 删除操作
	result = db.Delete(&user)
	if result.Error != nil {
		panic("删除用户失败")
	}
}

于此同时通过,GORM还有高级的操作

  1. 数据库索引的使用:

    • 合理地使用数据库索引可以提高查询性能。在定义模型时,我们可以使用GORM的标签来指定字段需要创建索引。
    • 但是,索引并非越多越好。过多的索引会增加写操作的成本,并占用额外的存储空间。我们需要根据实际查询和业务需求,选择适当的字段进行索引。
  2. 批量操作的优化:

    • 当需要进行批量的插入、更新或删除操作时,GORM提供了一些优化的方法。例如,可以使用CreateInBatches方法将大量的记录分

    • 批次地插入数据库,以避免一次性插入过多数据导致的性能问题。

      • 类似地,GORM还提供了UpdatesDelete等方法,可以批量更新和删除满足特定条件的记录。这样可以减少与数据库的交互次数,提高操作的效率。

      1. 使用事务:
        • 在并发环境或需要保证一组操作的原子性时,使用事务是非常重要的。GORM支持事务的开启、提交和回滚,可以确保一组操作要么全部成功执行,要么全部回滚。
        • 在使用事务时,我们需要注意事务的范围和持锁的时间。过长的事务可能导致锁竞争和性能下降,因此需要合理控制事务的粒度和持锁时间。
      2. 性能优化和监控:
        • 除了使用GORM提供的优化方法外,我们还可以通过其他手段对性能进行监控和优化。例如,可以使用数据库的性能分析工具,如Explain语句、慢查询日志等,来识别潜在的性能瓶颈和优化的点。
        • 另外,使用缓存、合理设计数据库表结构和查询语句,以及优化数据库参数设置等也是提高性能的重要手段。

总结

通过学习**《DATABASE/SQL 与 GORM 设计与实践**》课程,我对数据库和SQL的基础知识有了更深入的理解,并学习了如何使用GORM库进行数据库交互。我了解了GORM的设计原理和最佳实践,掌握了一些优化技巧和开发经验。在实际应用中,我将继续运用这些知识和技能,以提高代码的可读性、性能和可维护性,实现高效的数据库操作。

🎉感谢

青训营-青春造梦,技术未来 (bytedance.com)