mysql
最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
Mysql操作,我们一律使用Gorm做为默认ORM,我们的依赖注入完全无缝兼容gorm。在Web案例中我们有访问过数据库
最新api请参考,gorm官网
本教程只供参考
全功能 ORM
关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
Create,Save,Update,Delete,Find 中钩子方法
支持 Preload
、Joins
的预加载
事务,嵌套事务,Save Point,Rollback To Saved Point
Context,预编译模式,DryRun 模式
批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
复合主键,索引,约束
Auto Migration
自定义 Logger
灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
每个特性都经过了测试的重重考验
开发者友好
例如:
type User struct {
gorm.Model
Name string
Age sql.NullInt64
Birthday time.Time
Email string
gorm:"type:varchar(100);unique_index"
Role string gorm:"size:255"
//设置字段的大小为255个字节
MemberNumber string gorm:"unique;not null"
// 设置 memberNumber 字段唯一且不为空 Num int gorm:"AUTO_INCREMENT"
// 设置 Num字段自增
Address string gorm:"index:addr"
// 给 Address 创建一个名字是 addr
的索引
IgnoreMe int gorm:"-"
//忽略这个字段 }
GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID
作为主键,使用结构体名的 蛇形复数
作为表名,字段名的 蛇形
作为列名,并使用 CreatedAt
、UpdatedAt
字段追踪创建、更新时间
GORM 定义一个 gorm.Model
结构体,其包括字段 ID
、CreatedAt
、UpdatedAt
、DeletedAt
可导出的字段在使用 GORM 进行 CRUD 时拥有全部的权限,此外,GORM 允许您用标签控制字段级别的权限。这样您就可以让一个字段的权限是只读、只写、只创建、只更新或者被忽略
注意: 使用 GORM Migrator 创建表时,不会创建被忽略的字段
要使用不同名称的字段,您可以配置 autoCreateTim
、autoUpdateTim
标签
如果您想要保存 UNIX(毫/纳)秒时间戳,而不是 time,您只需简单地将 time.Time
修改为 int
即可
对于匿名字段,GORM 会将其字段包含在父结构体中,例如:
对于正常的结构体字段,你也可以通过标签 embedded
将其嵌入,例如:
并且,您可以使用标签 embeddedPrefix
来为 db 中的字段名添加前缀,例如:
声明 model 时,tag 是可选的,GORM 支持以下 tag: tag 名大小写不敏感,但建议使用 camelCase
风格
标签名
说明
column
指定 db 列名
type
列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not null
、size
, autoIncrement
… 像 varbinary(8)
这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INSTREMENT
size
指定列大小,例如:size:256
primaryKey
指定列为主键
unique
指定列为唯一
default
指定列的默认值
precision
指定列的精度
scale
指定列大小
not null
指定列为 NOT NULL
autoIncrement
指定列为自动增长
embedded
嵌套字段
embeddedPrefix
嵌入字段的列名前缀
autoCreateTime
创建时追踪当前时间,对于 int
字段,它会追踪时间戳秒数,您可以使用 nano
/milli
来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
autoUpdateTime
创建/更新时追踪当前时间,对于 int
字段,它会追踪时间戳秒数,您可以使用 nano
/milli
来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
index
uniqueIndex
与 index
相同,但创建的是唯一索引
check
<-
设置字段写入的权限, <-:create
只创建、<-:update
只更新、<-:false
无写入权限、<-
创建和更新权限
->
设置字段读的权限,->:false
无读权限
-
忽略该字段,-
无读写权限、
创建记录并更新给出的字段。
创建记录并更新未给出的字段。
要有效地插入大量记录,请将一个 slice
传递给 Create
方法。 将切片数据传递给 Create 方法,GORM 将生成一个单一的 SQL 语句来插入所有数据,并回填主键的值,钩子方法也会被调用。
使用 CreateInBatches
创建时,你还可以指定创建的数量,例如:
说明 初始化GORM时使用CreateBatchSize选项,所有的INSERT在创建record & associations时都会尊重这个选项
GORM允许用户定义的钩子被实现为beforeave, beforereate, AfterSave, AfterCreate。这些钩子方法将在创建记录时被调用,有关生命周期的详细信息请参考钩子
如果你想跳过钩子方法,你可以使用SkipHooks会话模式,例如
GORM支持创建 map[string]interface{}和[]map[string]interface{}{},例如:
注意当创建from map时,钩子不会被调用,关联不会被保存,主键值也不会被填回
ORM允许使用SQL表达式插入数据,有两种方法可以实现这个目标,create from map[string]interface{}或自定义数据类型,例如:
当创建一些带有关联的数据时,如果它的关联值不是零值,那么这些关联将被插入,并且它的hook方法将被调用
你可以用Select跳过保存关联,省略,例如:
你可以为带有default标签的字段定义默认值,例如:
然后,当为零值字段插入数据库时,将使用默认值
注意任何像0,",false这样的零值不会被保存到数据库中,对于那些定义了默认值的字段,你可能想要使用指针类型或Scanner/Valuer来避免这种情况,例如:
注意:你必须为在数据库中有默认值或虚拟/生成值的字段设置默认标记,如果你想在迁移时跳过默认值定义,你可以使用default:(-),例如:
当使用虚拟/生成的值时,您可能需要禁用其创建/更新权限,检查字段级权限
GORM为不同的数据库提供兼容的Upsert支持
在高级查询中还检出firststorinit和firststorcreate
查看原始SQL和SQL Builder以获取更多细节
GORM 提供了 First
、Take
、Last
方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1
条件,且没有找到记录时,它会返回 ErrRecordNotFound
错误
如果你想避免ErrRecordNotFound错误,你可以使用Find,比如db.Limit(1).Find(&user)
First, Last方法将根据主键找到第一个/最后一个记录顺序,它只在使用struct查询或提供模型值时有效,如果没有为当前模型定义主键,将根据第一个字段排序,例如:
通过使用内联条件,可以使用主键检索对象。使用字符串时要格外小心,以避免SQL注入,详细信息请参阅安全部分
注意:当使用struct查询时,GORM只会查询非零字段,这意味着如果你的字段的值是0,",false或其他零值,它不会被用于构建查询条件,例如
您可以使用map来构建查询条件,例如:
工作原理类似于Where。
建造NOT条件 工作原理类似于Where。
还可以在高级查询中检查组条件,它可以用于编写复杂的SQL
指定要从数据库检索的字段,默认情况下,选择所有字段
也可以查看智能选择字段
从数据库中检索记录时指定顺序
Limit指定要检索的记录的最大数量Offset指定在开始返回记录之前要跳过的记录的数量
关于如何制作分页器的签出分页
从模型中选择不同的值
Distinct 也可以使用Pluck Count
指定连接条件
你可以在单个SQL中使用连接急切加载关联,例如:
有关详细信息,请参阅预加载(即时加载)
扫描结果到一个结构的工作类似于查找
说明QueryFields模式将按所有字段的名称选择当前模型
GORM支持不同类型的锁,例如:
更多细节请参考原始SQL和SQL Builder
子查询可以嵌套在查询中,当使用* GORM . db对象作为参数时,GORM可以生成子查询
GORM允许在方法表的FROM子句中使用子查询,例如:
更容易编写带有组条件的复杂SQL查询
GORM支持sql命名参数。NamedArg或map[string]接口{}{},例如:
查看Raw SQL和SQL Builder了解更多细节
GORM允许扫描结果映射[string]interface{}或[]map[string]interface{},不要忘记指定模型或表,例如:
获取第一个匹配的记录或用给定的条件初始化一个新的实例(仅适用于struct或map条件)
用更多的属性初始化struct如果没有找到记录,这些Attrs将不会被用于构建SQL查询
为struct分配属性,无论是否找到,这些属性都不会用于构建SQL查询,最终数据也不会保存到数据库中
获取第一个匹配的记录或创建一个给定条件的新记录(仅适用于struct, map条件)
创建具有更多属性的结构,如果没有找到记录,这些属性将不会被用于构建SQL查询
为记录分配属性,不管是否找到记录,并将它们保存回数据库
优化器提示用于控制查询优化器选择某个查询执行计划,GORM 通过 gorm.io/hints
提供支持,例如:
索引提示允许向数据库传递索引提示,以防查询规划器搞混。
GORM支持遍历行
批量查询和处理记录
GORM允许hook在查询后被调用,当查询一个记录时,它将被调用,参考hook获取详细信息
从数据库查询单个列并扫描到一个切片,如果要查询多个列,则使用Select和scan代替
作用域允许您指定可以作为方法调用引用的常用查询
获取匹配记录计数
Save
会保存所有的字段,即使字段是零值
Updates
方法支持 struct
和 map[string]interface{}
参数。当使用 struct
更新时,默认情况下,GORM 只会更新非零值的字段
注意 当通过 struct 更新时,GORM 只会更新非零字段。 如果您想确保指定字段被更新,你应该使用
Select
更新选定字段,或使用map
来完成更新操作
如果您想要在更新时选定、忽略某些字段,您可以使用 Select
、Omit
如果您尚未通过 Model
指定记录的主键,则 GORM 会执行批量更新
如果在没有任何条件的情况下执行批量更新,默认情况下,GORM 不会执行该操作,并返回 ErrMissingWhereClause
错误
对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate
模式,例如:
获取受更新影响的行数
GORM 允许使用 SQL 表达式更新列,例如:
使用子查询更新表
如果您想在更新时跳过 Hook
方法且不追踪更新时间,可以使用 UpdateColumn
、UpdateColumns
,其用法类似于 Update
、Updates
GORM 提供了 Changed
方法,它可以被用在 Before Update Hook 里,它会返回字段是否有变更的布尔值
Changed
方法只能与 Update
、Updates
方法一起使用,并且它只是检查 Model 对象字段的值与 Update
、Updates
的值是否相等,如果值有变更,且字段没有被忽略,则返回 true
若要在 Before 钩子中改变要更新的值,如果它是一个完整的更新,可以使用 Save
;否则,应该使用 SetColumn
,例如:
如果指定的值不包括主属性,那么 GORM 会执行批量删除,它将删除所有匹配的记录
如果在没有任何条件的情况下执行批量删除,GORM 不会执行该操作,并返回 ErrMissingWhereClause
错误
对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate
模式,例如:
如果您的模型包含了一个 gorm.DeletedAt
字段(gorm.Model
已经包含了该字段),它将自动获得软删除的能力!
拥有软删除能力的模型调用 Delete
时,记录不会被从数据库中真正删除。但 GORM 会将 DeletedAt
置为当前时间, 并且你不能再通过正常的查询方法找到该记录。
如果您不想引入 gorm.Model
,您也可以这样启用软删除特性:
您可以使用 Unscoped
找到被软删除的记录
您也可以使用 Unscoped
永久删除匹配的记录
原生查询 SQL 和 Scan
Exec
原生 SQL
Row
& Rows
获取 *sql.Row
结果
获取 *sql.Rows
结果
sql.Rows
扫描至 model使用 ScanRows
将一行记录扫描至 struct,例如:
GORM 内部使用 SQL builder 生成 SQL。对于每个操作,GORM 都会创建一个 *gorm.Statement
对象,所有的 GORM API 都是在为 statement
添加/修改 Clause
,最后,GORM 会根据这些 Clause 生成 SQL
例如,当通过 First
进行查询时,它会在 Statement
中添加以下 Clause
然后 GORM 在 Query
callback 中构建最终的查询 SQL,像这样:
生成 SQL:
不同的数据库, Clause 可能会生成不同的 SQL,例如:
尽管很少会用到它们,但如果你发现 GORM API 与你的预期不符合。这可能可以很好地检查它们,例如:
模型是标准的 struct,由 Go 的基本数据类型、实现了 和 接口的自定义类型及其指针或别名组成
遵循 GORM 已有的约定,可以减少您的配置和代码量。如果约定不符合您的需求,
您可以将它嵌入到您的结构体中,以包含这几个字段,详情请参考
GORM 约定使用 CreatedAt
、UpdatedAt
追踪创建/更新时间。如果您定义了这种字段,GORM 在创建、更新时会自动填充
根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 获取详情
创建检查约束,例如 check:age > 13
,查看 获取详情
和 也支持批量插入
GORM 允许通过 方法选择特定的字段,如果您在应用程序中经常使用此功能,你也可以定义一个较小的结构体,以实现调用 API 时自动选择特定的字段,例如:
请参考优化了解更多细节
查看详细信息
当使用 Update
更新单个列时,你需要指定条件,否则会返回 ErrMissingWhereClause
错误,查看 获取详情。当使用了 Model
方法,且该对象主键有值,该值会被用于构建条件,例如:
对于更新操作,GORM 支持 BeforeSave
、BeforeUpdate
、AfterSave
、AfterUpdate
钩子,这些方法将在更新记录时被调用,详情请参阅
并且 GORM 也允许使用 SQL 表达式、的 Context Valuer 来更新,例如:
删除一条记录时,删除对象需要指定主键,否则会触发 ,例如:
GORM 允许通过内联条件指定主键来检索对象,但只支持整型数值,因为 string 可能导致 SQL 注入。查看 获取详情
对于删除操作,GORM 支持 BeforeDelete
、AfterDelete
Hook,在删除记录时会调用这些方法,查看 获取详情
注意 GORM 允许缓存预编译 SQL 语句来提高性能,查看 获取详情
GORM 支持 、map[string]interface{}{}
或 struct 形式的命名参数,例如:
在不执行的情况下生成 SQL
,可以用于准备或测试生成的 SQL,详情请参考
转到 获取如何在批量中查询和处理记录的信息, 转到 获取如何构建复杂 SQL 查询的信息
您可以自定义 Clause
并与 GORM 一起使用,这需要实现 接口
可以参考
之所以支持 Clause,是因为 GORM 允许数据库驱动程序通过注册 Clause Builder 来取代默认值,这儿有一个 的示例
GORM 定义了很多 ,其中一些 Clause 提供了你可能会用到的选项
GORM 提供了 接口,允许您修改语句,使其符合您的要求,这儿有一个 示例