前言

ORM全称Object Relational Mapping,是把编程语言中的Object/Struct数据类型映射到关系数据库中1张表,以下是详细映射关系。

 

gorm简介

面向github编程找一找Golang中比较流行的orm,

注意Django的orm是包含在Django web框架中的,而gorm有点像Python中的sqlalchemy它不限制你必须要在某个web框架中使用它。

gorm中文官方网站内含十分齐全的中文文档。

 

本文将围绕当前最近版本gorm v1.20.8展开。

go.mod

 

gorm安装

 

连接数据库

在golang中连接不同的数据就需要使用不同的driver驱动。

GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server

开始

  

Model定义

我们在创建Table的时可以通过设置struct字段的tag,对数 表名、字段进行属性设置。

结构体

--------------------------------

  

Mysql

-------------------------------------

 

Django orm的差别

当我们Django的model中修改了表字段需要先make magrations生成操作,然后再make magirate去数据库真正执行这次magration。保证了数据库的安全。

而gorm只要你执行db.AutoMigrate()就会实时修改表结构,但是当你使用Django orm 修改了数据库字段magration时经常报错Exist table让你不知所措。

 

查看gorm操作日志 

db.Debug可以帮助我们显示gorm对数据库的操作

日志内容

 

增删改查CURD

立即执行方法(Immediate Methods):查询只有执行了立即执行函数才会去数据库查询 First/Find/FirstrOrInit/FirstOrCreate/

内联条件 inline condition:就是把SQL查询条件当做参数传递到立即执行函数中执行。

gorm支持使用String、Struct&Map作为条件进行查询已经链样操作。

 

创建单条记录

 

批量创建

在生产环境之中如果你插入数据特别频繁,可以使用批量插入的方式进行优化。如果数据没有实时展示的要求。

 

 

 查询

new和make区别:make给map/channel/slince申请内存和容量返回值类型,new初始化基本类型string/int/结构体返回指针类型的变量

 

主键查询

Objects can be retrieved using primary key by using Inline Conditions.

Be extra careful with strings to avoid SQL Injection, check out Security section for details 

通过内联条件的方式,我们可以根据主键获取到数据库中的1/多条记录。

 

一般查询

 

Where 条件查询

 

使用Struct & Map & 切片进行查询

我们可使用结构体、map、slice把搜索条件组合起来。

 

 

Not 条件查询

我们可以使用Where指定筛选条件,也可以使用Not排除一些条件。

 

 

Or条件查询

我可以使用Or连接2个搜索条件。

 

内联条件查询

通过以上大量的实验你会发现我总会在Where/Not/Or里面组织搜索条件,然后再 .First/Find。

这是Where/Not/Or中的SQL需要借助立即执行方法 才真正把SQL发送到mysqld(服务端)执行,然后返回值,我们声明的变量才会获取到值。

 

您会发现.Find()和.First()t这些立即执行方法可以接收2个参数(dest interface{}, conds ...interface{})

第1个参数用于接收和保存服务端(mysqld)返回的结果、第2个用于客户端(MySQL)输入SQL搜索条件。

什么是内联条件查询呢?

就是我们在把接收查询结果的变量、SQL查询条件传递到.Find()/.First()/.Not()/.Or()这些立即执行函数中执行就属于内联条件查询。

 

设置查询选项

SetGetInstanceSetInstanceGet

Gorm 中有一些特性用到了这种机制,如迁移表格时传递表格选项。

 

我们在查询 SQL是可以设置添加1个行锁(在我查询这条记录的时候别人就无法修改这条数据了)

  

FirstOrInit查询

gorm的核心功能就是把数据库返回的1条记录转换成golang中的结构体并对字段进行赋值。

如果在某些情况下我的SQL查询没有返回任何记录,那我的stuct变量的全部字段就会使用零值。

可以使用 Attrs和Assign方法对 FirstOrInit返回的空记录 进行struct字段进行赋值。

attrs:获取匹配的第1条记录,否则根据给定的条件初始化一个新的对象 (仅支持 struct 和 map 条件)

Assign:不管记录是否找到,都将参数赋值给 struct变量。

 

FirstOrCreate插入数据

Attrs和Assign不仅可以对声明的结构体变量进行初始化,还可以指定FirstOrCreate将要创建的记录。

FirstOrCreate:获取匹配的第1条记录, 否则根据给定的条件创建一个新的记录 (仅支持 struct 和 map 条件)

Attrs:如果记录未找到,将使用attr中设置的参数创建 struct 和新记录.

Assign:不管记录是否找到,都将参数赋值给 struct 并保存至数据库.

 

子查询

 

Select选择字段

Select,指定你想从数据库中检索出的字段,默认会选择全部字段。

  

 

排序查询

 我们可以通过Order api对查询的数据进行排序

  

Limit & Offset

LimitOffset

  

count获取查询总量

CountSELECTcount

  

Group&Having 

分组和聚合

  

join连表

  

 

Pluck

SelectScan

Pluck可以帮助我们获取到table中的某1列数据并赋值给slice。

 

Scan

Find

Scan的功能类似于Find,可以把从数据库中查询到的结果映射到struct中。

 

Scope查询

func(*gorm.DB) *gorm.DB

Scopes可以帮助我们把常用的查询逻辑封装到1个函数里面,后期使用查询时Scope这个函数。

 

链式操作相关

 Django的Q查询可以做组合查询,gorm中的链式操作也可以。

 

更新 update

 

Save更新所有字段

 

Update更新1个字段

Model(&userObj)我在Model中能传了1个userObj,gorm会根据userObj中的id字段去数据库where需要更新的记录。

 

Updates同时更新多个字段

我们可以给update方法传1个map,同时更新多个字段。

 

Updates更新指定的字段

有时我们接收到的map可能会包含一些我们不需要更新的字段,那么如何指定有效字段、排除无效字段呢?

 

UpdateColumns 

UpdateColumns也叫无Hooks更新。

BeforeUpdateAfterUpdate
UpdatedAtAssociationsUpdateColumnUpdateColumns就不会更新UpdatedAt字段。UpdatedAt字段。

 

批量更新多条记录

UpdatedAt

 

全表更新

我想要1张表中的某个字段全部更新怎么办?还记得Django中的F在原数据的基础上+1?

 

删除delete

最后就是删除了~

删除1条记录

我跟可以根据对象删除一条记录,注意必须指定对象的主键否则会触发 批量 Delete,也可以根据主键直接删除1条记录。

 

批量删除

gorm中都是软删除。

 

全表删除

 清空表中的内容

 

表关联 

在关系型数据里表和表之间的关系:1对1(主键+外键联合唯一)、1对多(外键)、多对多(中间增加1张记录2个之间相互1对多关系的表),外键总在多的一方设置。

平时我们讨论表关系时有人会抛出 belongs to(属于)、多对1、1对多这些概念,此时你千万别懵逼。其实反映到数据库里还是外键。

以上2张表存在外键关联:

一对多:从球队角度来说一个球队拥有多个球员 即为一对多
多对一:从球员角度来说多个球员属于一个球队 即为多对一数据表间一对多关系如下图:

无论是1对多,还是多对1,本质在数据库里的体现还是1个外键。

 

外键连表查询

以上我们上面大量篇幅说主表从表,其实就是2个表存在外键关系。

根据自身业务需求设计外键就好了,我一般称在从表使用外键查询就属于正向连表,否则就是反向连表查询。

一个外键引发了太多没有意义的思考,好吧开始定义model和外键吧。

使用默认外键字段名称

 

自定义外键名称

以上我们通过默认的外键:使用拥有者(Role)的struct名+上主字段名做外键关联到了主表。也可以在从表自定义外键的名称。

 

自定义外键字段

我从表一定要外键到主表ID这个列?我想外键到其他列!

 

最终定义1个模型

 

正向和反向连表查询

 

多对多查询

我现在想把用户和角色变成多对多的关系。1个用户可以有多个角色,1个角色也可以被多个用户使用。这就不需要外键了,现在得使用1张中间关系表。

多对多查询最简单了