database/sql & GORM | 青训营笔记

66 阅读2分钟

数据库、sql及GORM

database/sql的设计原理

内部实现连接池的管理,给上层应用程序一些简单的操作接口,给下层数据库暴露一些driver和连接接口和操作接口

import (
    "database/sql"
    "time"
​
    _ "github.com/go-sql-driver/mysql"
)
​
// ...
​
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
    panic(err)
}
// See "Important settings" section.
db.SetConnMaxLifetime(time.Minute * 3)
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(10)

池技术:

  • 空间换时间,浪费服务器的硬件资源,换取运行效率。
  • 池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源。
  • 当服务器进入正式运行阶段,开始处理客户请求的时候,如果它需要相关的资源,可以直接从池中 获取,无需动态分配。
  • 当服务器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用释放资源。
//Driver接口
type Driver interface {
    Open(name string) (Conn, error)
}

DB连接的类型:直接连接Conn,预编译Stmt,事务Tx

处理返回数据的方式:

  1. Exec/ExecContext -> Result
  2. Query -> Rows(Columns)
  3. QueryRow -> Row(Rows简化)

GORM

设计简洁、功能强大、自由扩展的全功能ORM

ORM(Object Relational Mapping)框架采用元数据来描述对象与关系映射的细节,元数据一般采用XML格式,并且存放在专门的对象一映射文件中。简单理解为一种框架的格式

gorm框架是go的一个数据库连接及交互框架,一般用于连接关系型数据库。

特性:

  • 全功能 ORM
  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 PreloadJoins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • Auto Migration
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

约定优于配置:

  • 表名为struct name的snake_ cases 复数格式
  • 字段名为field name的snake_ case 单数格式
  • ID/ ld字段为主键,如果为数字,则为自增主键
  • CreatedAt字段,创建时,保存当前时间
  • UpdatedAt字段,创建、更新时,保存当前时间
  • gorm.DeletedAt字段,默认开启soft delete模式
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")
  }
​
  // Migrate the schema
  db.AutoMigrate(&Product{})
​
  // Create
  db.Create(&Product{Code: "D42", Price: 100})
​
  // Read
  var product Product
  db.First(&product, 1) // find product with integer primary key
  db.First(&product, "code = ?", "D42") // find product with code D42
​
  // Update - update product's price to 200
  db.Model(&product).Update("Price", 200)
  // Update - update multiple fields
  db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // non-zero fields
  db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
​
  // Delete - delete product
  db.Delete(&product, 1)
}