使用GORM进行增删改查 | 青训营

84 阅读5分钟

这是我在字节跳动青训营学习的第28天,也是我参加《第六届青训营笔记伴读》的第四篇笔记

GORM

什么是 ORM

Object Relational Mapping:对象关系映射,就是将结构体与数据库中的表进行一一对应

什么是GORM

"设计简洁,功能强大,自由扩展的全功能ORM"

  • 设计原则: API精简、测试优先、最小惊讶、灵活扩展、无依赖 可信赖

GORM使用

安装

go get -u gorm.io/gorm 
go get -u gorm.io/driver/mysql

连接数据库(以mysql为例)

func main() {  
dsn := "username:password@tcp(localhost:3306)/database?charset=utf8mb4&parseTime=True&loc=Local"  
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})  
if err != nil {  
fmt.Println("无法连接到数据库:", err)  
return  
}

注意:想要正确的处理 time.Time ,您需要带上 parseTime 参数, (更多参数) 要支持完整的 UTF-8 编码,您需要将 charset=utf8 更改为 charset=utf8mb4 查看 此文章 获取详情。

Model定义

已知ORM是结构体与表关系的一一对应,那么要操作表就要先定义结构体,也就是Model,为了方便模型定义,GORM内置了一个gorm.Model结构体。gorm.Model是一个包含了IDCreatedAtUpdatedAtDeletedAt四个字段的Golang结构体。

// gorm.Model 定义 
type Model struct { 
ID uint `gorm:"primary_key"` 
CreatedAt time.Time 
UpdatedAt time.Time 
DeletedAt *time.Time 
}

但是我不用,就是玩

By the way

GORM 倾向于约定优于配置 默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAtUpdatedAt 字段追踪创建、更新时间。

如果您遵循 GORM 的约定,您就可以少写的配置、代码。 如果约定不符合您的实际要求,GORM 允许你配置它们

支持的结构体标记

标签名说明
column指定列名
type列数据类型
primaryKey将列定义为主键
default定义列的默认值
not null指定列为Not NULL

新增 Create

package main  
  
import (  
"fmt"  
"gorm.io/driver/mysql"  
"gorm.io/gorm"  
)  
  
type UserInfo struct {  
ID uint  
Name string  
Age uint  
Adress string `gorm:"default:山西"`  
}  
  
func main() {  
dsn := "root:root@tcp(localhost:3306)/tiktok?charset=utf8mb4&parseTime=True&loc=Local"  
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})  
if err != nil {  
fmt.Println("无法连接到数据库:", err)  
return  
}  
  
err = db.AutoMigrate(&UserInfo{})  
if err != nil {  
panic("failed to migrate")  
}  

//添加数据  
u1 := UserInfo{  
Name: "小蓝",  
Age: 19,  
Adress: "山西",  
}  
  
users := []UserInfo{  
{Name: "Jinzhu", Age: 18, Adress: "上海"},  
{Name: "Jackson", Age: 19, Adress: "北京"},  
}  
db.Create(users)  
db.Create(&u1)  
// db.Create(&UserInfo{1,"小明", 13, "山西"})  
  
}

在以上案例中,我们先创建结构体,并定Adress字段默认为山西,然后我们将结构体自动迁移到数据库,数据库会自动生成对应的表,表名为user_infos,

插入数据又分为单个插入与批量插入,若要有效地插入大量记录,请将一个切片传递给 Create 方法。GORM 将生成一个单独的 SQL 语句来插入所有数据并回填主键值,钩子方法也将被调用。当记录可以分成多个批处理时,它将开始一个事务。

查询 Select

一般查询

// 根据主键查询第一条记录
var user User
result := db.First(&user)
fmt.Println(result.RowsAffected) // 返回找到的记录数
fmt.Println(result.Error)        // returns error or nil
//// 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;

// 查询所有的记录
db.Find(&users)
//// SELECT * FROM users;

// 查询指定的某条记录(仅当主键为整型时可用)
db.First(&user, 10)
//// SELECT * FROM users WHERE id = 10;

db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;

db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);

//主键为字符串
db.First(&user, "id = ?", "第一")
// SELECT * FROM users WHERE id = "第一"

where

// Get first matched record
db.Where("name = ?", "jinzhu").First(&user)
//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;

// Get all matched records
db.Where("name = ?", "jinzhu").Find(&users)
//// SELECT * FROM users WHERE name = 'jinzhu';

// <>
db.Where("name <> ?", "jinzhu").Find(&users)
//// SELECT * FROM users WHERE name <> 'jinzhu';

// IN
db.Where("name IN (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)
//// SELECT * FROM users WHERE name in ('jinzhu','jinzhu 2');

// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
//// SELECT * FROM users WHERE name LIKE '%jin%';

// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
//// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;

// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
//// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';

// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
//// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

更新 Update

Save()默认会更新该对象的所有字段,即使你没有赋值。

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)

// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;

若你只想更新某些字段

// Update with conditions 
db.Model(&User{}).Where("active = ?", true).Update("name", "hello") 
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;
// User's ID is `111`: 
db.Model(&user).Update("name", "hello") 
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

无hook更新

上面的更新操作会自动运行 model 的 BeforeUpdate, AfterUpdate 方法,更新 UpdatedAt 时间戳, 在更新时保存其 Associations, 如果你不想调用这些方法,你可以使用 UpdateColumnUpdateColumns

    // 更新单个属性,类似于 `Update` 
    db.Model(&user).UpdateColumn("name", "hello") 
    // UPDATE users SET name='hello' WHERE id = 111; 
    // 更新多个属性,类似于 `Updates`
    db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18}) 
    // UPDATE users SET name='hello', age=18 WHERE id = 111;

删除 Delete

警告 删除记录时,请确保主键字段有值,GORM 会通过主键去删除记录,如果主键为空,GORM 会删除该 model 的所有记录。

// 删除现有记录
db.Delete(&email)
//// DELETE from emails where id=10;

db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;

db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;

db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);

// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

// 为删除 SQL 添加额外的 SQL 操作
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
//// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);

批量删除

如果指定的值不包括主属性,那么 GORM 会执行批量删除,它将删除所有匹配的记录。

db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
//// DELETE from emails where email LIKE "%jinzhu%";

db.Delete(Email{}, "email LIKE ?", "%jinzhu%")
//// DELETE from emails where email LIKE "%jinzhu%";

参考