Go框架三件套-Gorm详解 | 青训营笔记

120 阅读6分钟

“这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

Gorm是Goland语言一个已经迭代了10年+的功能强大的ORM库,在字节内部被广泛使用并且拥有非常丰富的开源扩展。

目录结构:

  1. Gorm基本使用
    • 支持数据库
    • 创建
    • 更新
    • 删除
    • 查询
  2. Gorm事务
    • 开启事务
    • 回滚事务
    • 提交事务
    • 自动提交事务
  3. Hook
  4. 性能提高
  5. Gorm生态

ORM(Object Relational Mapping):对象关系映射,其主要作用是在编程中把面向对象的概念和数据库中表的概念对应起来,解决了对象和关系型数据库之间的数据交互问题。

关系型数据库:使用关系模型(二维表格模型)来组织数据的数据库而一个关系型数据库就是由二维表及其之间的关系组成的一个数据组织。最大优点就是事务一致性。其维护代价为比较差的读写性能。 主要代表:SQL Server Oracle Mysql

非关系型数据库:通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定,常用于存储非结构化的数据。 主要代表:Redis

Grom基础使用

通过gorm根据不同驱动支持不同数据库,驱动方式连接数据库,目前支持MySQL、SQLServer、PostgreSQL、SQLite。 1675932931522.png

1675931942333.png

gorm model对应的就是数据库里的一张表,用于承载或表示一条数据,它的字段对应的就是表中对应的字段。使用名为ID的字段做主键。

定义表名:TableName()接口返回字段就是表名,没有的话就会使用蛇形负数来做表名。

Gorm创建数据: 1675932047373.png

  • 如何处理数据冲突
    1675932197658.png
  • 如何使用默认值 1675932260882.png

Gorm查询数据: 1675932105662.png

  • First使用踩坑
    First查询不到数据会返回ErrRecordNotFound。
    Find查询多条数据,查询不到不会返回错误。
  • 零值(0、""、false)查询
    使用结构体作为条件查询只会查询非零值字段。
    使用Map构建查询条件可以查到零值。

Gorm更新数据1675932534449.png

  • 零值更新 使用结构体更新只会更新非零值。
    Map更新或Select选择字段可更新零值。

Gorm删除数据
逻辑删除(软删除):没有实际删除数据,只是将数据标记为已删除。
物理删除(硬删除):真的给数据删了。 从数据价值和项目规模来说:建议小型系统和低价值数据采用物理删除。大型系统和高价值数据采用软删除

Gorm提供了完备的软删能力,提供了gorm.DeletedAt去赋予Model软删除能力。拥有软删除能力的Model调用Delete时记录不会被从数据库中真正删除,但Gorm会将DeleteAt置为当前时间,不能再通过正常的查询方法找到该记录。但可以使用Unscoped查询到被软删的数据。

  • 硬删除使用: 1675932693309.png
  • 软删除使用 1675932758517.png

实现tips:

  • 查询数据是否存在,存在则更新,不存在则创建逻辑实现
     // 查询+save实现
     var u1 User
     db.find(&User, "id=?",1)
     User.name = "ccc"
     db.Save(&User)
    

  • 链式调用时where语句等都是去拼SQL的,只有当执行Find、first、update、create等才是真正去执行SQL了,当我们调用完这类API再去追条件的时候,条件已经不生效了。我们需要获取它的结果的时候需要给链式调用的这个结构体返回回来。
  • 天然支持防数据注入

Gorm事务:

  • 事务解释: 业务中一个高频需求是:有一批连续的操作,这一批操作要么全部成功,要么就可以像没有发生过一样,不要由于部分未成功而导致脏数据产生。如果没有事务,我们处理用户下单的业务场景,就要超级多的代码去handle各种错误、清理各种脏数据、避免可能的bug,比如下单成功却由于数据库宕机导致没有扣款。为了提高开发效率、降低开发成本,就需要数据库能提供一种保证:将一组操作看作一个单元,这一单元可以全部成功,在部分失败的情况下,可以完全回滚,就像没有发生,这一组操作称为事务(Transaction)。

我们需要使用事务去保证数据的一致性,如果对数据一致性要求比较强的话一定要使用事务。

数据一致性:
缓存中有数据,缓存数据=数据库值
缓存中无数据,数据库值=最新值

保证数据一致性:
对于一个数据库操作(事务)来说,保证四个特性ACID即可保证数据一致性。

ACID:
原子性(atomicity):一个事务中的所有操作不可分割,要么全成功,要么全失败;
一致性(consistency):一个事务执行前与执行后数据的完整性必须保持一致;
隔离性(isolation):一个事务的执行,不能被其他事务干扰,多并发时事务之间要相互隔离;
持久性(durability):一个事务一旦被提交,它对数据库中数据的改变是永久性的。

Gorm提供了Begin、Commit、Rollback方法用于使用事务 1675933461327.png

  • Begin方法:开启事务
    会返回一个gorm对象,后续一定要使用返回的对象。最终返回的对象已经是开启事务后并且它的链接是已经固化的,再也不会去使用链接池里的链接了。

  • RollBack方法:回滚事务

  • Commit方法:提交事务

  • Transaction方法:自动提交事务 避免用户漏写Commit、Rollback

    当涉及多表忘记为每个处理失败添加回滚事务时,会导致数据库链接泄露。推荐使用Transaction解决该问题。

    1675933501368.png

Hook

Gorm提供了CURD(数据库基本操作中的创建读取更新删除)的Hook能力,Hook是在创建、查询、更新、删除等操作之前、之后自动调用的函数。 如果Hool返回错误,Gorm将停止后续操作并回滚事务。 调用Hook后本身会添加默认事务,Hook操作也在默认事务里面可以保证数据一致性. 1675933579052.png

性能提高

1675933597809.png

  1. 关闭默认事务 对于写操作(创建、更新、删除),为了确保数据完整性,Gorm会将它们封装在事务内运行。但这会降低性能,可以使用SkipDefaultTransaction关闭默认事务。

  2. 缓存预编译语句提高后续调用速度 使用PrePareStmt缓存预编译语句可以提高后续调用的速度

Gorm生态

Gorm拥有非常丰富的扩展生态:

1675933671598.png

参考

  1. zhuanlan.zhihu.com/p/78619241
  2. juejin.cn/post/694657…
  3. juejin.cn/post/684490…