设计模式之 Database/SQL 与 GORM 实践 | 青训营笔记

47 阅读3分钟
  1. 理解database / sql
  1. 基本用法
  • 常见错误:事务没有commit、close,因为有时候异常会使close无法正常执行,所以需要手动关闭
  • 可以在import的时候添加不同数据库的driver,这样就可以用同样的方式同样的代码去支持不一样的数据库
  1. 设计原理
    应用程序
    <--api操作接口--> 上层应用
    database / sql 连接池
    <--连接接口/操作接口--> 数据库Driver
    数据库
  • 连接池
    • 配置
      • func (db *DB) SetConnMaxIdleTime(d time.Duration)
      • func (db *DB) SetConnMaxLifeTime(d time.Duration)
      • func (da *DB) SetMaxIdleConns(n int)
      • func (da *DB) SetMaxOpenConns(n int)
    • 状态
      • func (db *DB) Stats() DBStats
    • DB连接的类型
      • 直接连接 / Conn
      • 预编译 / Stmt
      • 事务 / Tx
    • 处理返回数据的方式
      • Exec /ExecXontext -> Result
      • Query / QueryContext -> Rows(Columns)
      • QueryRow / QueryRowContext -> Row(Rows 简化)
  1. GORM使用简介

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

  • 基本用法 - CRUD
    • 读取
    • 更新某个/多个字段
    • 批量更新
    • 删除
  • 模型定义 - 惯例约束
    • 表名为struct name的snake_cases复数格式
    • 字段名为field name的snake_case单数格式
    • ID /Id字段为主键,如果为数字,则为自增主键
    • CreatedAt字段,创建时,保存当前时间
    • UpdateAt字段,创建、更新时,保存当前时间
    • gorm。DeletedAt字段时,默认开启soft delete模式
  • 关联操作
    • CRUD
    • Preload / Joins预加载
    • 级联删除
  1. GORM设计原理

应用程序
GORM <--api操作接口-->
database / sql
<--连接接口/操作接口-->
数据库

  1. SQL的生成 image.png chain method:sql里的子句 finisher method:操作类型

  2. SQL这样生成的原因

    • 自定义Clause Builder
      • 不同数据库甚至不同版本的数据库支持的SQL不同
      • 根据自己数据库的版本对参数进行初始化,生成不同的SQL,自定义子句builder
    • 扩展子句
      • 扩展select子句后
      • 扩展from子句后
      • 自由扩展子句前中后
    • 选择子句
      • 不同的数据库(如PostgreSQL、MySQL、Clickhouse等)的sql操作有差异。
      • 可以隐藏掉差异,在不改变代码的时候灵活去扩展、支持各种数据库。(即自定义它所支持的数据库子句类型,在不改变代码的情况下兼容不同的数据库)
  3. 插件是怎么工作的
    finisher method -> 决定statement类型 -> 执行callbacks -> 生成SQL并执行
    callbacks类型:create query update delete row raw

  4. 插件这样工作的原因 - 灵活定制、自由扩展

    • 多租户 (在每个操作后加上一个自定义的过滤方法,防止操作事故)
    • 多数据库、读写分离(主数据库-写,从数据库-读;可以同时设置多组读写数据库,指定某一组的读/写数据库读取内容)
  5. ConnPool
    根据内容判断执行的是读/写数据库,来完成当前的请求 image.png

  • 预编译,只需要做一次解析,加快执行速度
    • 全局模式,所有DB操作都会预编译并缓存(缓存不含参数部分)
    • 会话模式,后续会话的操作都会预编译并缓存(只针对当前会话)
  • 流程
    • 查找缓存的预编译SQL
    • 未找到,将收到的SQL和Vars预编译
    • 使用缓存的预编译SQL执行
  • 通过一行配置迅速提升软件性能 interpolateParams=false 它的预编译用完就扔掉,跟前面的预编译缓存不一样
  1. GORM最佳实践
  1. 数据序列化与SQL表达式
  2. 批量数据操作
  3. 代码复用、分库分表、Sharding
  4. 混沌工程
  5. Logger / Trace
  6. Migrator
  7. Gen代码生成 / Raw SQL
  8. 安全