GORM 极速入门 - 掘金


本站和网页 https://juejin.cn/post/6903337526811951118 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

GORM 极速入门 - 掘金
首页 首页
沸点
课程
直播
活动
竞赛
商城
APP
插件 搜索历史
清空
创作者中心
写文章 发沸点 写笔记 写代码 草稿箱 创作灵感
查看更多
会员
登录
注册
GORM 极速入门
代码与野兽
2020年12月07日 10:36
·  阅读
8851
一、基础概念
ORM(Object Relational Mapping),意思是对象关系映射。
数据库会提供官方客户端驱动,但是需要自己处理 SQL 和结构体的转换。
使用 ORM 框架让我们避免转换,写出一些无聊的冗余代码。理论上 ORM 框架可以让我们脱离 SQL,但实际上还是需要懂 SQL 才可以使用 ORM。
我本人是非常排斥使用 ORM 框架的,原因有两点。
一、不自由,我不能随心所欲的控制我的数据库。
二、性能差,比官方客户端驱动直接编写 SQL 的效率低 3-5 倍。
不过 ORM 也有很多优点,它可以在一定程度上让新手避免慢 SQL。
也有一些文章讨论过 ORM 的利弊。比如这篇:orm_is_an_antipattern。
总的来说,是否使用 ORM 框架取决于一个项目的开发人员组织结构。
老手渴望自由,新手需要规则。世界上新手多,老手就要做出一些迁就。
gorm 是一款用 Golang 开发的 orm 框架,目前已经成为在 Golang Web 开发中最流行的 orm 框架之一。本文将对 gorm 中常用的 API 进行讲解,帮助你快速学会 gorm。
除了 gorm,你还有其他选择,比如 sqlx 和 sqlc。
二、连接 MySQL
gorm 可以连接多种数据库,只需要不同的驱动即可。官方目前仅支持 MySQL、PostgreSQL、SQlite、SQL Server 四种数据库,不过可以通过自定义的方式接入其他数据库。
下面以连接 mySQL 为例,首先需要安装两个包。
import (
"gorm.io/driver/mysql" // gorm mysql 驱动包
"gorm.io/gorm"// gorm
复制代码
连接代码。
// MySQL 配置信息
username := "root" // 账号
password := "xxxxxx" // 密码
host := "127.0.0.1" // 地址
port := 3306 // 端口
DBname := "gorm1" // 数据库名称
timeout := "10s" // 连接超时,10秒
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
// Open 连接
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect mysql.")
复制代码
三、声明模型
每一张表都会对应一个模型(结构体)。
比如数据库中有一张 goods 表。
CREATE TABLE `gorm1`.`无标题` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`price` decimal(10, 2) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
复制代码
那么就会对应如下的结构体。
type Goods struct {
Id int
Name string
Price int
复制代码
约定
gorm 制定了很多约定,并按照约定大于配置的思想工作。
比如会根据结构体的复数寻找表名,会使用 ID 作为主键,会根据 CreateAt、UpdateAt 和 DeletedAt 表示创建时间、更新时间和删除时间。
gorm 提供了一个 Model 结构体,可以将它嵌入到自己的结构体中,省略以上几个字段。
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
复制代码
嵌入到 goods 结构体中。
type Goods struct {
gorm.Model
Id int
Name string
Price int
复制代码
这样在每次创建不同的结构体时就可以省略创建 ID、CreatedAt、UpdatedAt、DeletedAt 这几个字段。
字段标签 tag
在创建模型时,可以给字段设置 tag 来对该字段一些属性进行定义。
比如创建 Post 结构体,我们希望 Title 映射为 t,设置最大长度为 256,该字段唯一。
type Post struct {
Title string `gorm:"column:t, size:256, unique:true"`
复制代码
等同于以下 SQL。
CREATE TABLE `posts` (`t, size:256, unique:true` longtext)
复制代码
更多功能可参照下面这张表。
标签名说明column指定 db 列名type列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INSTREMENTsize指定列大小,例如:size:256primaryKey指定列为主键unique指定列为唯一default指定列的默认值precision指定列的精度scale指定列大小not null指定列为 NOT NULLautoIncrement指定列为自动增长embedded嵌套字段embeddedPrefix嵌入字段的列名前缀autoCreateTime创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nanoautoUpdateTime创建/更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milliindex根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情uniqueIndex与 index 相同,但创建的是唯一索引check创建检查约束,例如 check:age > 13,查看 约束 获取详情<-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限->设置字段读的权限,->:false 无读权限-忽略该字段,- 无读写权限
四、自动迁移
在数据库的表尚未初始化时,gorm 可以根据指定的结构体自动建表。
通过 db.AutoMigrate  方法根据 User 结构体,自动创建 user 表。如果表已存在,该方法不会有任何动作。
type User struct {
gorm.Model
UserName string
Password string
db.AutoMigrate(&User{})
复制代码
建表的规则会把 user 调整为复数,并自动添加 gorm.Model 中的几个字段。由于很多数据库是不区分大小写的,如果采用 camelCase 风格命名法,在迁移数据库时会遇到很多问题,所以数据库的字段命名风格都是采用 underscorecase 风格命名法,gorm 会自动帮我们转换。
等同于以下 SQL。
CREATE TABLE `gorm1`.`无标题` (
`id` bigint(0) UNSIGNED NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) NULL DEFAULT NULL,
`updated_at` datetime(3) NULL DEFAULT NULL,
`deleted_at` datetime(3) NULL DEFAULT NULL,
`user_name` longtext CHARACTER SET utf8 COLLATE utf8_bin NULL,
`password` longtext CHARACTER SET utf8 COLLATE utf8_bin NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_users_deleted_at`(`deleted_at`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
复制代码
五、创建数据 Craete Insert
使用 db.Create  方法,传入结构体的指针创建。
user := User{UserName: "l", Password: "ddd"}
result := db.Create(&user)
复制代码
等同于以下 SQL。
INSERT INTO
`users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
'2020-12-03 17:19:00.249',
'2020-12-03 17:19:00.249',
NULL,
'l',
'ddd')
复制代码
gorm 会自动维护 created_at、updated_ad 和 deleted_at 三个字段。
插入后返回的常用数据
下面是一些常用的插入数据。
fmt.Println("ID:", user.ID) // 插入的主键
fmt.Println("error:", result.Error) // 返回的 error
fmt.Println("rowsAffected:", result.RowsAffected) // 插入的条数
复制代码
只插入指定字段
通过 Select 选择指定字段。
user := User{UserName: "lzq", Password: "ccc"}
result := db.Select("UserName").Create(&user)
复制代码
等同于以下 SQL。
INSERT INTO `users` (`user_name`) VALUES ('lzq')
复制代码
_需要注意:使用 select 时不会自动维护 created_at、updated_ad 和 deleted_at。
不插入指定字段
使用 Omit 方法过滤一些字段。
result := db.Omit("UserName").Create(&user)
复制代码
批量插入
当需要批量插入时,传入一个切片即可。
users := []User{
{UserName: "lzq", Password: "aaa"},
{UserName: "qqq", Password: "bbb"},
{UserName: "gry", Password: "ccc"},
db.Create(&users)
复制代码
等同于以下 SQL。
INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
( '2020-12-03 18:08:47.478', '2020-12-03 18:08:47.478', NULL, 'lzq', 'aaa' ),(
'2020-12-03 18:08:47.478',
'2020-12-03 18:08:47.478',
NULL,
'qqq',
'bbb'
),(
'2020-12-03 18:08:47.478',
'2020-12-03 18:08:47.478',
NULL,
'gry',
'ccc')
复制代码
分批批量插入
在某些情况下,users 的数量可能非常大,此时可以使用 CreateInBatches 方法分批次批量插入。
假设有 6 条 user 数据,你想每次插入 2 条,这样就会执行 3 次 SQL。
users := []User{
{UserName: "lzq", Password: "aaa"},
{UserName: "qqq", Password: "bbb"},
{UserName: "gry", Password: "ccc"},
{UserName: "lzq", Password: "aaa"},
{UserName: "qqq", Password: "bbb"},
{UserName: "gry", Password: "ccc"},
db.CreateInBatches(&users, 2)
复制代码
等同于依次执行以下 3 句 SQL。
INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
( '2020-12-03 18:15:20.602', '2020-12-03 18:15:20.602', NULL, 'lzq', 'aaa' ),(
'2020-12-03 18:15:20.602',
'2020-12-03 18:15:20.602',
NULL,
'qqq',
'bbb')
复制代码
INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
( '2020-12-03 18:15:20.616', '2020-12-03 18:15:20.616', NULL, 'gry', 'ccc' ),(
'2020-12-03 18:15:20.616',
'2020-12-03 18:15:20.616',
NULL,
'lzq',
'aaa')
复制代码
INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
( '2020-12-03 18:15:20.621', '2020-12-03 18:15:20.621', NULL, 'qqq', 'bbb' ),(
'2020-12-03 18:15:20.621',
'2020-12-03 18:15:20.621',
NULL,
'gry',
'ccc'
复制代码
CreateInBatches  方法的内部是使用 for 进行切割切片的,并没有使用 goroutine。
六、查询数据 Read Selete
查询单个对象
gorm 提供了 First、Take、Last 方法。它们都是通过 LIMIT 1  来实现的,分别是主键升序、不排序和主键降序。
user := User{}
// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;
// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;
// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
复制代码
如果没有查询到对象,会返回 ErrRecordNotFound 错误。
result := db.First(&user)
errors.Is(result.Error, gorm.ErrRecordNotFound)
result.RowsAffected
复制代码
根据主键查询
在 First/Take/Last 等函数中设置第二个参数,该参数被认作是 ID。可以选择 int 或 string 类型。
db.First(&user, 10)
db.First(&user, "10")
复制代码
选择 string 类型的变量时,需要注意 SQL 注入问题。
查询多个对象(列表)
使用 Find 方法查询多个对象。
users := []User{}
result := db.Find(&users)
复制代码
返回值会映射到 users 切片上。
依然可以通过访问返回值上的 Error 和 RowsAffected 字段获取异常和影响的行号。
result.Error
result.RowsAffected
复制代码
设置查询条件 Where
gorm 提供了万能的 Where 方法,可以实现 =、<>、IN、LIKE、AND、>、<、BETWEEN 等方法,使用 ? 来占位。
db.Where("name = ?", "l").First(&user)
// SELECT * FROM users WHERE user_name = 'l' ORDER BY id LIMIT 1;
// 获取全部匹配的记录
db.Where("name <> ?", "l").Find(&users)
// SELECT * FROM users WHERE user_name <> 'l';
// IN
db.Where("name IN ?", []string{"lzq", "qqq"}).Find(&users)
// SELECT * FROM users WHERE user_name IN ('lzq','qqq');
// LIKE
db.Where("name LIKE ?", "%l%").Find(&users)
// SELECT * FROM users WHERE user_name LIKE '%l%';
// AND
db.Where("name = ? AND age = ?", "lzq", "aaa").Find(&users)
// SELECT * FROM users WHERE user_name = 'lzq' AND password = aaa;
// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2020-11-01 00:00:00' AND '2020-11-08 00:00:00';
复制代码
Where 快速设置条件的方法
传递 Struct、Map 和 切片时,可以实现更简便的设置条件。
db.Where(&User{UserName:"lzq", Password:"aaa"}).Find(&user)
db.Where(map[string]interface{}{"user_name": "lzq", "password": "aaa"}).Find(&user)
复制代码
结构体和 Map 的效果几乎是相等的。
SELECT
FROM
`users`
WHERE
`users`.`user_name` = 'lzq'
AND `users`.`password` = 'aaa'
AND `users`.`deleted_at` IS NULL
复制代码
两者唯一的不同之处在于 struct 中的零值字段不会查询。比如 0、""、false。
切片是查询主键。
db.Where([]int{10, 11}).Find(&user)
复制代码
等同于如下 SQL。
SELECT
FROM
`users`
WHERE
`users`.`id` IN ( 10, 11 )
AND `users`.`deleted_at` IS NULL
复制代码
所有的查询,gorm 都会默认设置 tabel.deleted_at IS NULL  查询条件。
除了 Where 方法外,还有内联查询的方式,但是不推荐同时使用两种风格。
db.Find(&user, "user_name = ?", "lzq")
// SELECT * FROM users WHERE user_name = "lzq";
复制代码
其他查询 Not & Or
gorm 还提供了 Not 和 Or 方法,但不推荐使用,因为 Where 同样可以实现两者的功能,记忆额外的 API 无疑会增加心智负担。
db.Where("password = ?", "aaa").Not("user_name", "l").Or("id > ?", 10).Find(&users)
复制代码
等同于如下 SQL。
SELECT * FROM `users` WHERE (( PASSWORD = 'aaa' )
AND `user_name` <> 108
OR id > 10
AND `users`.`deleted_at` IS NULL
复制代码
选取特定字段 Select
使用 Select 方法。
db.Select("password").Where(&User{UserName:"lzq"}).Find(&user)
复制代码
等同于以下 SQL。
SELECT
`password`
FROM
`users`
WHERE
`users`.`user_name` = 'lzq'
AND `users`.`deleted_at` IS NULL
复制代码
其他操作
排序 Order
db.Order("user_name desc, password").Find(&users)
复制代码
等同于以下 SQL。
SELECT
FROM
`users`
WHERE
`users`.`deleted_at` IS NULL
ORDER BY
user_name DESC,
PASSWORD
复制代码
分页 Limit Offset
Limit 和 Offset 可以单独使用,也可以组合使用。
db.Limit(3).Find(&users)
db.Offset(3).Find(&users)
db.Limit(2).Offset(3).Find(&users)
复制代码
等同于以下 SQL。
SELECT
FROM
`users`
WHERE
`users`.`deleted_at` IS NULL
LIMIT 2 OFFSET 3
复制代码
分组 Group Having
根据 username 统计用户名的重复。
result := []map[string]interface{}{}
db.Model(&User{}).
Select("user_name, SUM( id ) AS nums").
Group("user_name").
Find(&result)
复制代码
等同于以下 SQL。
SELECT
user_name,
SUM( id ) AS nums
FROM
users
GROUP BY
user_name;
复制代码
去重 Distinct
result := []string{}
db.Model(&User{}).
Distinct("user_name").
Find(&result)
复制代码
等同于以下 SQL。
SELECT DISTINCT
user_name
FROM
users
复制代码
连表 Join
在业务中不太建议使用 Join,而是使用多条查询来做多表关联。
七、更新数据 Update
更新所有字段
使用 Save 方法更新所有字段,即使是零值也会更新。
db.First(&user)
user.UserName = ""
db.Save(&user)
复制代码
等同于以下 SQL。
UPDATE `users`
SET `created_at` = '2020-12-03 15:12:08.548',
`updated_at` = '2020-12-04 09:17:40.891',
`deleted_at` = NULL,
`user_name` = '',
`password` = 'ddd'
WHERE
`id` = 1
复制代码
更新单列
使用 Model 和 Update 方法更新单列。
可以使用结构体作为选取条件,仅选择 ID。
user.ID = 12
db.Model(&user).Update("user_name", "lzq")
复制代码
等同于以下 SQL。
UPDATE `users`
SET `user_name` = 'lzq',
`updated_at` = '2020-12-04 09:16:45.263'
WHERE
`id` = 12
复制代码
也可以在 Model 中设置空结构体,使用 Where 方法自己选取条件。
db.Model(&User{}).Where("user_name", "gry").Update("user_name", "gry2")
复制代码
等同于以下 SQL。
UPDATE `users`
SET `user_name` = 'gry2',
`updated_at` = '2020-12-04 09:21:17.043'
WHERE
`user_name` = 'gry'
复制代码
还可以组合选取条件。
user.ID = 20
db.Model(&user).Where("username", "gry").Update("password", "123")
复制代码
等同于以下 SQL。
UPDATE `users`
SET `password` = '123',
`updated_at` = '2020-12-04 09:25:30.872'
WHERE
`username` = 'gry'
AND `id` = 20
复制代码
更新多列
使用 Updates 方法进行更新多列。支持 struct 和 map 更新。当更新条件是 struct 时,零值不会更新,如果确保某列必定更新,使用 Select 选择该列。
更新选定字段 Selete Omit
使用 Select 和 Omit 方法。
批量更新
如果在 Model 中没有设置 ID,默认是批量更新。
八、删除数据 Delete
删除单条
使用 Delete 方法删除单条数据。但需要指定 ID,不然会批量删除。
user.ID = 20
db.Delete(&user)
复制代码
等同于以下 SQL。
UPDATE `users`
SET `deleted_at` = '2020-12-04 09:45:32.389'
WHERE
`users`.`id` = 20
AND `users`.`deleted_at` IS NULL
复制代码
设置删除条件
使用 Where 方法进行设置条件。
db.Where("user_name", "lzq").Delete(&user)
复制代码
等同于以下 SQL。
UPDATE `users`
SET `deleted_at` = '2020-12-04 09:47:30.544'
WHERE
`user_name` = 'lzq'
AND `users`.`deleted_at` IS NULL
复制代码
根据主键删除
第二个参数可以是 int、string。使用 string 时需要注意 SQL 注入。
db.Delete(&User{}, 20)
复制代码
等同于以下 SQL。
UPDATE `users`
SET `deleted_at` = '2020-12-04 09:49:05.161'
WHERE
`users`.`id` = 20
AND `users`.`deleted_at` IS NULL
复制代码
也可以使用切片 []int、[]string 进行根据 ID 批量删除。
db.Delete(&User{}, []string{"21", "22", "23"})
复制代码
等同于以下 SQL。
UPDATE `users`
SET `deleted_at` = '2020-12-04 09:50:38.46'
WHERE
`users`.`id` IN ( '21', '22', '23' )
AND `users`.`deleted_at` IS NULL
复制代码
批量删除
空结构体就是批量删除。
软删除(逻辑删除)
如果结构体包含 gorm.DeletedAt 字段,会自动获取软删除的能力。
在调用所有的 Delete 方法时,会自动变为 update 语句。
UPDATE users SET deleted_at="2020-12-04 09:40" WHERE id = 31;
复制代码
在查询时会自动忽略软删除的数据。
SELECT * FROM users WHERE user_name = 'gry' AND deleted_at IS NULL;
复制代码
查询软删除的数据
使用 Unscoped 方法查找被软删除的数据。
db.Unscoped().Where("user_name = gry").Find(&users)
复制代码
永久删除(硬删除 物理删除)
使用 Unscoped 方法永久删除数据。
user.ID = 14
db.Unscoped().Delete(&user)
复制代码
九、原生 SQL
除了上面的封装方法外,gorm 还提供了执行原生 SQL 的能力。
执行 SQL 并将结果映射到变量上
使用 Raw 方法配合 Scan 方法。
可以查询单条数据扫描并映射到结构体或 map 上。
db.
Raw("SELECT id, record_id, user_name, password FROM users WHERE id = ?", 25).
Scan(&user)
复制代码
也可以映射到其他类型上。
var userCount int
db.
Raw("SELECT count(id) FROM users").
Scan(&userCount)
复制代码
如果返回结果和传入的映射变量类型不匹配,那么变量的值不会有变化。
只执行 SQL 不使用结果
使用 Exec 方法执行 SQL。
db.Exec("UPDATE users SET password=? WHERE id = ?", "abcdefg", 22)
复制代码
十、钩子 Hook
gorm 提供了 Hook 功能。可以在创建、查询、更新和删除之前和之后自动执行某些逻辑。
创建
gorm 提供了 4 个创建钩子,BeforeCreate、AfterCreate 和 BeforeSave、AfterSave。
假设现在需要添加一个 RecordID,并且在每次创建时生成一个 16 位的 uuid。
type User struct {
gorm.Model
RecordID string
UserName string
Password string
复制代码
除此之外,还希望在存储之前打印生成的 uuid,在存储之后打印创建后的 id。
实现方式就是给模型结构体 User 添加 BeforeCreate 和 AfterCreate 两个方法。
func (u *User) BeforeCreate(tx *gorm.DB) error {
u.RecordID = uuid.New().String()
fmt.Println("创建 User 开始,UUID 为:", u.RecordID)
return nil
func (u *User) AfterCreate(tx *gorm.DB) error {
fmt.Println("创建 User 完毕,ID 为:", u.ID)
return nil
复制代码
更新
更新的 Hook 是 BeforeUpdate、AfterUpdate 和 BeforeSave、AfterSave,用法与创建一致。
查询
查询的 Hook 是 AfterFind,用法与创建一致。
删除
删除的 Hook 是 BeforeDelete 和 AfterDelete,用法与创建一致。
除了查询的 Hook 外,其他 Hook 都是在事务上运行的,一旦在函数中 return error 时,就会触发事务回滚。
十一、事务
事务保证了事务一致性,但会降低一些性能。gorm 的创建、修改和删除操作都在事务中执行。
如果不需要可以在初始化时禁用事务,可以提高 30% 左右的性能。
全局关闭事务
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
SkipDefaultTransaction: true,
})
复制代码
会话级别关闭事务
tx := db.Session(&Session{SkipDefaultTransaction: true})
// 继续执行 SQL 时使用 tx 对象
tx.First(&user)
复制代码
在事务中执行 SQL
假设现在需要添加一个 company 表存储公司信息,并创建一个 company_users 表用于关联用户和公司的信息。
// 创建结构体
type Company struct {
gorm.Model
RecordID string
Name string
type CompanyUser struct {
gorm.Model
RecordID string
UserID string
CompanyID string
// 自动迁移
db.AutoMigrate(&Company{})
db.AutoMigrate(&CompanyUser{})
// 创建一家公司
company := Company{Name: "gxt"}
company.RecordID = uuid.New().String()
db.Save(&company)
// 在事务中执行
db.Transaction(func(tx *gorm.DB) error {
// 创建用户
u := User{UserName: "ztg", Password: "333"}
result := tx.Create(&u)
if err := result.Error; err != nil {
return err
// 查询公司信息
company2 := Company{}
tx.First(&company2, company.ID)
// 关联用户和公司
result = tx.Create(&CompanyUser{UserID: u.RecordID, CompanyID: company2.RecordID})
if err := result.Error; err != nil {
return err
return nil
})
复制代码
十二、日志
gorm 默认实现了一个 Logger,它仅输出慢 SQL。
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // Log level
Colorful: false, // 禁用彩色打印
},
复制代码
日志的级别可以配置,可以设置 Silent、Error、Warn、Info。
全局模式开启
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
复制代码
会话模式开启
tx := db.Session(&Session{Logger: newLogger})
复制代码
自定义 Logger
gorm 提供了一个 Interface 接口,可以通过实现这个接口来自定义 Logger。
type Interface interface {
LogMode(LogLevel) Interface
Info(context.Context, string, ...interface{})
Warn(context.Context, string, ...interface{})
Error(context.Context, string, ...interface{})
Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error)
复制代码 分类: 后端 标签: Go 相关推荐
liedmirror
1年前
Go
后端
[Golang-Gorm] Gorm的分页操作 这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战 一、前言 在使用Go语言进行后端开发时,个人比较喜欢的一个orm是Gorm,也是Go后端开发中使用最多的orm(star最多)。而且它还是 9125
程序员读书
4年前
Go
Golang数据库编程之GORM库入门 在上一篇文章中我们讲解了使用Go语言的标准库sql/database包操作数据库的过程,虽然使用sql/database包操作数据也是挺方便的,但是需要自己写每一条SQL语句,因此我们可能会自己再度进行封装,以便更好地使用,而使用现有Go语言开源ORM框架则是代替自己封装的一个… 8464
31
用户3916551519621
1年前
ORM
后端
gORM操作MySQL ORM 框架 ORM:Object Relational Mapping —— 对象关系映射。 作用: 通过操作结构体对象,来达到操作数据库表的目的。 通过结构体对象,来生成数据库表。 优点: SQL 4428
评论
ag9920
9月前
后端
Go
数据库
GORM 强大的代码生成工具 —— gorm/gen GORM 进入到 2.0 时代之后解决了很多 jinzhu/gorm 时代的问题,整体的扩展性以及功能也更强大。但总有一些绕不开的问题困扰着我们。为此 GORM 也推出了自己的【代码生成工具】:gen 6521
30
TNT
1年前
Go
GORM GORM ORM 什么是ORM? Object Relational Mapping 对象 关系 映射 对象:Go中的结构体实例,Java中用类 关系:关系型数据库 ,如mysql ORM优缺点 优点 385
评论
dlutzhangyi
3年前
Go
gorm踩坑笔记1 最近在用gorm查询满足某个条件的所有记录中最新的记录,代码可参考下面的例子,具体查询语句如下所示,目的是查询满足条件host_id=1的所有记录中按时间倒序,然后返回最新的记录。 执行结果,从执行结果中发现,返回了第一条记录,显然不是想要的结果,预期返回的应该是第二条记录,而… 2574
go4it
2年前
Go
聊聊gorm的Transaction gorm的DB提供了Transaction方法,相当于一个事务模板,自动commit或者rollback,它提供了func(tx *gorm.DB) error参数用于自定义事务内的数据库操作。 2649
评论
第八共同体
3年前
MySQL
gorm的简单使用和注意事项 业务上,我想要获取当前最新的一条记录。使用了Order()方法和First()方法组合,倒叙后取第一条记录即是最新的一条记录,但是,查看gorm的First方法可以看出: 1.3w
亚洲第一中锋_哈达迪
1年前
Go
gorm如何处理查询为空 前言 gorm是go语言的一个orm框架 gorm对查询结果为空的处理主要体现在gorm.ErrRecordNotFound上,这是预定义的一个错误类型。字面上理解,当查询不到数据时框架会返回该错误, 7428
浪狼郎
9月前
Go
gorm不并发安全 gorm并没有承诺并发安全,gorm只是提供了一套符合使用习惯的并发范式,来兼顾性能和并发安全。如果你的使用习惯不符合gorm预想的习惯,则可能会出现并发安全。 1911
ourlang
1年前
后端
GORM基本操作 「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」。 概览 全功能 ORM (无限接近) 关联 (Has One, Has Many, Belongs To, Many To 891
评论
go4it
2年前
Go
聊聊gorm的logger gorm的logger提供了Interface接口,可以自己实现并全局设置或者在session级别设置;gorm默认的logger实现了logger.Interface接口定义的LogMode、Info、Warn、Error、Trace方法。 1877
评论
树獭叔叔
10月前
后端
Go
Gorm CRUD操作详解 1. 创建操作 db.Create() 创建单条记录 返回的result是一个gorm.DB对象,后续文章我们会详细讲解这个对象,这里我们只需要知道他会携带一些我们连接数据库执行SQL需要的信息以及执 1129
30
Conqueror712
4月前
Go
后端
Gin + Gorm实战CRUD丨学习记录 本文介绍了通过Gin + Gorm + MySQL + Navicat实现了最基础Go的CRUD操作。 1.9w
140
13
go4it
2年前
Go
聊聊gorm的Model gorm定义了ID、CreatedAt、UpdatedAt、DeletedAt属性;其中Create的时候会自动设置CreatedAt、UpdatedAt,Update的时候会自动更新UpdatedAt;CreatedAt、UpdatedAt支持 UnixSecond、Unix… 1416
评论
go4it
2年前
Go
聊聊gorm的Unscoped gorm的Unscoped方法设置tx.Statement.Unscoped为true;针对软删除会追加SoftDeleteDeleteClause,即设置deleted_at为指定的时间戳;而callbacks的Delete方法在db.Statement.Unscoped为f… 1405
点赞
评论
JustLorain
5月前
Go
后端
使用 Hertz 和 Gorm 快速搭建 Web 服务 简介 在之前的文章中我们使用 Hertz 编写了一个简单的 demo 帮助快速上手 Hertz 这款 Golang HTTP 框架,本节我们将加入 Gorm 框架和 Hertz 框架一起学习一个简单的 1825
20
大摩羯先生
2年前
Go
后端
Golang周边 | Gorm使用汇总 本文是关于Gorm基本使用的汇总,Golang语言的ORM框架,结合简单示例进行论述和说明,作为学习使用 3949
评论
go4it
2年前
Go
聊聊gorm的读写分离 gorm的dbresolver实现了Plugin接口,它针对Create、Update、Delete方法注册了dr.switchSource;针对Query、Row注册了dr.switchReplica;switchSource及switchReplica方法在当前连接没有开启… 2126
点赞
友情链接:
超凡:我有一把超凡手枪
大唐:签到七年,被长孙皇后曝光
开局被熊孩子刮车,我反手买超跑
我在海贼当神棍
比干挖心的故事
比我大六岁的那个哥哥
比水更解渴的东西
python数据统计建模
我在异界当老板全文免费阅读
比翼连枝当日愿小说
代码与野兽
公众号@代码与野兽 @ 保密
关注
私信
获得点赞
 5,144
文章被阅读
 539,695
相关文章 前端小白的几个坏习惯 214点赞  ·  171评论你需要知道的 12 个常用的 JavaScript 函数 567点赞  ·  72评论揭秘web3元宇宙千万级项目的财富密码:凭什么一个div卖一千块? 150点赞  ·  88评论你到底懂不懂JavaScript?来做做这12道面试题试试! 281点赞  ·  76评论2022年能让你早点下班的36个JavaScript实用函数! 455点赞  ·  49评论 目录