DATABASE/SQL 与 GORM 设计与实践| 青训营笔记

238 阅读2分钟

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

database/sql

基本用法

建立 driver

//常规写法
db, err := sql.Open(
    mysql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
)
//更好的写法,使用结构体
connector, err := mysqk.NewConnector(&mysql.Config{
    User:        "gorm",
    Passwd:      "gorm",
    Net:         "tcp",
    Addr:        "127.0.0.1:3306",
    DBName:      "gorm",
    ParseTime:    true,
})
db := sql.OpenDB(connector)

sql操作

rows, err := db.Query("select id, name from user where id = ?", 1)
//最后一定要close
defer func(){
    err = rows.Close()
}
//使用 Next() 方法和 Scan() 方法来实现数据库的中数据的读取
var users []User
for rows.Next(){
   var user User
   err := rows.Scan(&user.ID, &user.Name)
   
   users = append(users, user)
}
if rows.Err() != nil{
//
}

GORM

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

基本用法

建立 driver

db, err := gorm.Open(
    mysql.Open("user:password@tcp(127.0.0.1:3306)/hello")
)

select 操作

var user User
err = db.Select("id","name").Find(&users, 1).Error

模型定义

约定优于配置

下面是一些惯例约定:

  • 表名是 stuct name 的复数格式
  • 字段名是field name 的单数格式
  • ID / Id 字段为主键,如果是数字,则为自增主键
  • CreatedAt 字段,创建时保存当前时间
  • UpdatedAt 字段,创建、更新时保存当前时间
  • DeletedAt 字段,默认开启 soft delete 模式

设计原理

SELECT * FROM user WHERE role <> "manager" AND age > 35 ORDER BY age desc LIMIT 100

使用GORM可以代替为

db.Where("role <> ?", "manager").Where("age > ?", 35).Limit(100).Order("age desc").Find(&user)

GORM STATEMENT 由 GORM Clauses 和 Finisher Method来构成

其中 GORM Clauses 包括了多个 Chain Method

执行流程:Finisher Method => 决定 Statement 类型 => 执行 Callbacks => 生成 SQL 并执行

多租户

插件在工作时会强制根据TenantID来进行过滤

多数据库、读写分离

使用 Write 模式: 从 sources db 读取 指定 Resolver : 从 secondary 的 replicas db 中读取 指定 Resolver 和 Write 模式: 从 secondary 的 sources db 读取

ConnPool

一行代码提高SQL效率,关闭SQL预编译

interpolateParams=false

Dialector

GORM 实践

SQL表达式更新创建

  1. 通过gorm.Expr来使用SQL表达式

  2. 使用GORMValuer来使用SQL表达式

  3. 通过*gorm.DB使用SubQuery

SQL表达式查询

  1. 使用gorm.Expr

  2. Struct定义GORMValuer

  3. 自定义查询SQL实现接口clause.Expression

  4. 使用SubQuery

批量创建/查询

使用CreateInBatches()方法,以某个数量为单位进行分组创建

使用FindInBatches()方法,以某个数量为单位进行分组查找

批量数据加速操作

  1. 关闭默认事务

  2. 默认批量导入回调用 Hooks 方法,使用Skiphooks跳过

  3. 使用 Prepared Statement

  4. 混合使用

Gen代码生成

//生成自定义SQL静态代码
g:=gen.NewGenerator(gen.Config{
    OutPath: "../dal/query",
})
g.ApplyBasic(model.User{})//生成对应的CURD API
g.ApplyInterface(func(query method.Query) {}, model.User{})//给User生成Query Interface方法
g.Execute()

//查询
user, err := query.User.FindUser(10,"xxx", 16)

安全

拼接存在危险,会引起SQL注入,应以参数的形式传入