前言
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张中间关系表。
多对多查询最简单了