GORM快速入门 | 青训营

259 阅读5分钟

简介

ORM(Object Relation Mapper),顾名思义ORM是一种描述对象与数据库表之间映射的一种元数据描述,GORM则是Go语言关于映射的描述。使用GORM可以让我们在完成数据层逻辑处理时简化代码,高效完成功能。

安装

首先需要将GORM所需要的一些包导入到你的项目中,如下(驱动我选择为mysql的驱动,可自行选择):

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

快速开始

package main

import (
  "gorm.io/gorm"
  "gorm.io/driver/mysql"
)

type Product struct {
  gorm.Model
  Code  string
  Price uint
}

func main() {
  dsn := "root:123456@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"
  db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
  if err != nil {
    fmt.Println("failed to connect database")
  }

  // 创建表
  db.AutoMigrate(&Product{})

  // Create -插入一条记录
  db.Create(&Product{Code: "D42", Price: 100})

  // Read
  var product Product
  db.First(&product, 1) // 根据整型主键查找
  db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录

  // Update - 将 product 的 price 更新为 200
  db.Model(&product).Update("Price", 200)
  // Update - 更新多个字段
  db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
  db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})

  // Delete - 删除 product
  db.Delete(&product, 1)
}

约定

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

创建(Create)

GORM的API可以理解为一种将sql语句拆分为附加选择条件和决定类型的API,如我们在SELECT * FROM users WHERE id = 1 ORDER BY id LIMIT 1其中FROM users就是一种决定类型的API,而WHERE后的选择条件可以为附加类型的。以上sql使用GORM可写为:db.First(&user, 1)

当使用GORM对表中的数据进行插入操作时,首先需要构建一个模型(Model),也可理解为一种结构体,如果想通过map等其他集合构建模型的话需要使用Model()指明所代表的的Model。当然本人不喜欢这种方式,感觉有些多此一举。

简单且通用的插入

单条记录插入:

user := User{Name: "juejin", Age: 18, Birthday: time.Now()}

result := db.Create(&user) // 通过数据的指针来创建(插入)

多条记录插入:

// 创建users切片
users := []User{
    User{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
    User{Name: "Jackson", Age: 19, Birthday: time.Now()},
}

result := db.Create(*users)//传递一个切片来插入多行

根据Map创建

GORM 支持从map[string]interface{}和进行创建[]map[string]interface{}{},例如:

db.Model(&User{}).Create(map[string]interface{}{
  "Name": "juejin", "Age": 18,
})

// 从[]map[string]interface{}{}批量插入
db.Model(&User{}).Create([]map[string]interface{}{
  {"Name": "juejin_1", "Age": 18},
  {"Name": "juejin_2", "Age": 20},
})

查询(Query)

查询单个对象

GORM 提供了FirstTake,Last方法从数据库中检索单个对象,它LIMIT 1在查询数据库时添加条件。

// 获取按主键排序的第一条记录 
db.First(&user) 
// SELECT * FROM users ORDER BY id LIMIT 1;  

// 获取一条记录,无指定顺序
db.Take(&user)  
// SELECT * FROM users LIMIT 1;  

// 获取最后一条记录,按主键 desc 排序
db.Last(&user)  
// SELECT * FROM users ORDER BY id DESC LIMIT 1;

使用主键检索对象

First(),在第二个参数中填入一个数值即可使用主键检索,如:

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 用户 WHERE id IN (1,2,3); 

当目标对象具有主值时,将使用主键来构建条件,例如:

var user = User{ID: 10 }  
db.First(&user)  
// SELECT * FROM users WHERE id = 10; 

var result User 
db.Model(User{ID: 10 }).First(&result) 
// SELECT * FROM users WHERE id = 10; 

检索所有对象

// 获取所有记录
result := db.Find(&users)  
// SELECT * FROM users;

条件

string 条件

// 获取第一条匹配记录
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;

// 获取所有匹配记录
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';

内联条件

First(),Find()中传递不同类型的参数实现条件查询的效果,方法类似Where

// Get by primary key if it were a non-integer type
db.First(&user, "id = ?", "string_primary_key")
// SELECT * FROM users WHERE id = 'string_primary_key';

db.Find(&user, "name = ?", "jinzhu")
// SELECT * FROM users WHERE name = "jinzhu";

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

// Struct
db.Find(&users, User{Age: 20})
// SELECT * FROM users WHERE age = 20;

// Map
db.Find(&users, map[string]interface{}{"age": 20})
// SELECT * FROM users WHERE age = 20;

Not条件和Or条件

方法类似Where,详细可进入GORM官方文档优雅的使用查询

更新(Update)

更新单列

更新单列使用Update()方法,传入的是修改的属性。注:在使用查询的前必须有查找操作。

// 有条件的修改
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello' WHERE active=true;

// user.ID = 111
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello'WHERE id=111;

// 既有修改条件,对象里也有数值
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello' WHERE id=111 AND active=true;

更新多列

Updates()支持structmap[string]interface{},用它更新时struct默认只更新非零字段

// update by struct
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18 WHERE id = 111;

// update by map
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false WHERE id=111;

更新选定的字段

如果要更新选定的字段或更新时忽略某些字段,可以使用Select(),Omit()

// 用户 ID 为 111:
 db.Model(&user).Select( "name" ).Updates( map [ string ] interface {}{ "name" : "hello" , "age" : 18 , "active" : false }) 
// UPDATE users SET name='hello' WHERE id=111;

db.Model(&user).Omit( "name" ).Updates( map [ string ] interface {}{ "name" : "hello" , "age" : 18 , "active" : false }) 
// UPDATE users SET age=18, active=false WHERE id=111;

删除(Delete)

删除一条记录

删除一条记录时,删除对象需要指定主键,否则会触发批量删除

// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;

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

根据主键删除

GORM 允许通过主键和内联条件来删除记录,它可以使用数字

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("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%";