Golang学习&DATABASE/SQL与GORM 设计与实践 | 青训营笔记

392 阅读4分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记。

DATABASE/SQL与GORM 设计与实践

1.理解 database/sql

  • 连接数据库
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)
  • DB连接的几种类型
    • 直接连接/Conn
    • 预编译/Stmt
    • 事务/TX
  • 处理返回数据的几种方式
    • Exec/ ExecContext -> Result
    • Query / QueryContext -> Rows (Columns)
    • QueryRow / QueryRowContext -> Row (Rows简化)

2.GORM基础使用

GORM:设计简洁、功能强大、自由扩展的全功能ORM (对象关系映射)

  • 设计原则:API精简、测试优先、最小惊讶、灵活扩展、无依赖 可信赖

  • 功能完善:

    • 关联:一对一、一对多、单表自关联、多态;Preload、Joins 预加载、级联删除;关联模式;自定义关联表
    • 事务:事务代码块、嵌套事务、Save Point
    • 多数据库、读写分离、命名参数、Map、子查询、分组条件、代码共享、SQL表达式(查询、创建、更新)、自动选字段、查询优化器
    • 字段权限、软删除、批量数据处理、Propared Stmt、自定义类型、命名策略、虚拟字段、自动track 时间、SQLBuilder、Logger
    • 代码生成、复合主键、Constraint、Prometheus、Auto Migration、真·跨数据库兼容
    • 多模式灵活自由扩展
    • Dovelopor Friondly

    - 简单创建连接

    import (
      "gorm.io/driver/mysql"
      "gorm.io/gorm"
    )
    ​
    func main() {
      // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
      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{})
    }
    

    - 高级配置

    db, err := gorm.Open(mysql.New(mysql.Config{
      DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
      DefaultStringSize: 256, // string 类型字段的默认长度
      DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
      DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
      DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
      SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
    }), &gorm.Config{})
    

    - CRUD

    image-20220516164647282

- 模型定义

type User struct {
  ID           uint
  Name         string
  Email        *string
  Age          uint8
  Birthday     *time.Time
  MemberNumber sql.NullString
  ActivedAt    sql.NullTime
  CreatedAt    time.Time
  UpdatedAt    time.Time
}

- 约定大于配置

  • GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间。
  • 遵循 GORM 已有的约定,可以减少您的配置和代码量。如果约定不符合您的需求,GORM 允许您自定义配置它们。

使用 ID 作为主键

默认情况下,GORM 会使用 ID 作为表的主键。

type User struct {
  ID   string // 默认情况下,名为 `ID` 的字段会作为表的主键
  Name string
}

你可以通过标签 primaryKey 将其它字段设为主键

// 将 `UUID` 设为主键
type Animal struct {
  ID     int64
  UUID   string `gorm:"primaryKey"`
  Name   string
  Age    int64
}

复数表名

GORM 使用结构体名的 蛇形命名 作为表名。对于结构体 User,根据约定,其表名为 users

TableName

您可以实现 Tabler 接口来更改默认表名,例如:

type Tabler interface {
    TableName() string
}
​
// TableName 会将 User 的表名重写为 `profiles`
func (User) TableName() string {
  return "profiles"
}

简单总结:

  • GORM是一种对象关系映射ORM框架,数据表对应结构体,数据行对应结构体实例,数据库字段对应结构体字段。
  • 在gorm中,表名默认就是结构体名称的复数,也可以通过方法或者db.Table("表名")自定义表名;
  • 列名由两个单词组成,在数据库中默认转小写后用下划线链接;
  • 如果结构体有ID字段则默认ID字段为主键。
  • 另外,GORM内置了一个gorm.Model结构体。gorm.Model是一个包含了ID, CreatedAt, UpdatedAt, DeletedAt四个字段的Golang结构体,可以将其嵌入到自己的结构体中。(如果模型内置了gorm.model有DeletedAt字段,则调用Delete删除该记录时,将会设置DeletedAt字段为当前时间,而不是直接将记录从数据库中删除,即软删除)
  • gorm中支持的结构体tag:
Type    指定列数据类型
Size    指定列大小, 默认值255
PRIMARY_KEY    将列指定为主键
UNIQUE    将列指定为唯一
NOT NULL    将列指定为非 NULL
Column    指定列名
default  设置默认值
例子:
查询

db.Select("name, age").Order("age desc").Limit(3).Find(&user, "name = ?", "jinzhu")
db.Select("name, age").Order("age desc").Limit(3).Where("name = ?","jinzhu").Find(&users)
修改
// 根据给定的条件更新单个属性
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// 使用 map 更新多个属性,只会更新其中有变化的属性
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// 使用 struct 更新多个属性,只会更新其中有变化且为非零值的字段
db.Model(&user).Updates(User{Name: "hello", Age: 18})

如果你想更新或忽略某些字段,你可以使用 SelectOmit

删除
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
db.Delete(Email{}, "email LIKE ?", "%jinzhu%")
  • 在 GORM 中使用多个立即执行方法时,后一个立即执行方法会复用前一个立即执行方法的条件 (不包括内联条件,find中写的条件) 。立即执行方法是指那些会立即生成SQL语句并发送到数据库的方法,一般是CRUD方法,如:Create, First, Find, Take, Save, UpdateXXX, Delete, Scan, Row, Rows…
  • db.debug 可以返回查询的sql语句。