GORM使用笔记

GORM介绍及优点特性

Gorm 是 Golang 的一个 orm 框架。ORM 是通过实例对象的语法,完成关系型 数据库的操作,是"对象-关系映射"(Object/Relational Mapping) 的缩写。使用 ORM 框架可以让我们更方便的操作数据库。

Gorm官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server

国产的go-orm框架,中文文档齐全,对开发者友好,支持主流数据库。
优点:

  • 全功能 ORM
  • 关联 (拥有一个,拥有多个,属于,多对多,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 Preload、Joins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To to Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,锁,Optimizer/Index/Comment Hint,命名参数,子查询
    复合主键,索引,约束
  • 自动迁移
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

GORM的安装使用

## 安装好go环境之后用go命令安装gorm
go get -u gorm.io/gorm     
## 安装你要使用的相应数据库驱动。这里以MySQL驱动为例,GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server
go get -u gorm.io/driver/mysql  

GORM连接MySQL数据库示例代码

package models

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/plugin/soft_delete"
	"yixiang.co/go-mall/pkg/global"

	//"gorm.io/plugin/soft_delete"
	"log"
	"os"
	"time"
	"yixiang.co/go-mall/pkg/casbin"
)

var db *gorm.DB


type BaseModel struct {
	Id int64 `gorm:"primary_key" json:"id"`
	UpdateTime time.Time `json:"updateTime" gorm:"autoUpdateTime"`
	CreateTime time.Time `json:"createTime" gorm:"autoCreateTime"`
	IsDel soft_delete.DeletedAt `json:"isDel" gorm:"softDelete:flag"`
}

// Setup initializes the database instance
func Setup() {
	var err error
	var connStr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local",
		global.YSHOP_CONFIG.Database.User,
		global.YSHOP_CONFIG.Database.Password,
		global.YSHOP_CONFIG.Database.Host,
		global.YSHOP_CONFIG.Database.Name)
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
		logger.Config{
			SlowThreshold: time.Second,   // 慢 SQL 阈值
			LogLevel:      logger.Info, // 日志级别
			IgnoreRecordNotFoundError: true,   // 忽略ErrRecordNotFound(记录未找到)错误
			Colorful:      true,         // 禁用彩色打印
		},
	)

	db, err = gorm.Open(mysql.Open(connStr), &gorm.Config{
		Logger: newLogger,
	})

	if err != nil {
		log.Printf("[info] gorm %s", err)
	}

	sqlDB, err := db.DB()
	if err != nil {
		log.Printf("[info] gorm %s", err)
	}

	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxIdleConns(10)

	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	sqlDB.SetMaxOpenConns(100)

	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)

	global.YSHOP_DB = db

	casbin.InitCasbin(db)

}
// addExtraSpaceIfExist adds a separator
func addExtraSpaceIfExist(str string) string {
	if str != "" {
		return " " + str
	}
	return ""
}
package conf

type Database struct {
	Type        string `mapstructure:"type" yaml:"type"`
	User        string `mapstructure:"user" yaml:"user"`
	Password    string `mapstructure:"password" yaml:"password"`
	Host        string `mapstructure:"host" yaml:"host"`
	Name        string `mapstructure:"name" yaml:"name"`
	TablePrefix string `mapstructure:"table-prefix" yaml:"table-prefix"`
}

yml文件:

database:
  type: 'mysql'
  user: 'root'
  password: 'root'
  host: '127.0.0.1:3306'
  name: 'yshop_go'
  table_prefix:

默认约定配置

默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间。

遵循 GORM 已有的约定,可以减少配置和代码量。如果约定不符合需求,GORM 允许自定义配置它们。

GORM 默认使用ID作为表的主键

type User struct {
// 默认情况下,名为 `ID` 的字段会作为表的主键 Name string 
ID  string 
}

GORM 默认使用与表关联的结构体的蛇形命名的复数形式作为表的名称

例子:
struct: userinfo 默认表名:user_infos

gorm指定临时表名写法

// 根据 User 的字段创建 `deleted_users` 表
db.Table("deleted_users").AutoMigrate(&User{})

// 从另一张表查询数据
var deletedUsers []User
db.Table("deleted_users").Find(&deletedUsers)
// SELECT * FROM deleted_users;

db.Table("deleted_users").Where("name = ?", "jinzhu").Delete(&User{})
// DELETE FROM deleted_users WHERE name = 'jinzhu';

gorm内置Model结构体

GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt。

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

  • 声明 model 时,tag 是可选的,GORM 支持以下 tag: tag 名大小写不敏感,但建议使用驼峰 camelCase 命名风格。
  • Model的标签tag:
    标签名 说明
    column: 指定 db 表列名
    type: 列数据类型,推荐使用兼容性好的通用类型
    serializer: 指定如何序列化/反序列化到数据库, e.g: serializer:json/gob/unixtime
    size: 指定列的数据大小/长度, e.g: size:256
    primaryKey: 指定列作为主键
    unique: 指定列唯一
    default: 指定列为默认值
    precision: 指定列的精度
    scale: specifies column scale
    not null: 指定列 NOT NULL
    autoIncrement: 指定列为自增列
    autoIncrementIncrement : auto increment step, controls the interval between successive column values
    embedded: 嵌入字段
    embeddedPrefix: 嵌入字段的列名前缀
    autoCreateTime: 记录创建时间
    autoUpdateTime: 记录创建/更新时间
    index: 根据选项创建索引
    uniqueIndex: 唯一索引
    check: 创建检查约束, eg: check:age > 13, refer Constraints
    <- : 设置字段的写权限
    <-:create create-only field,
    <-:update update-only field,
    <-:false no write permission,
    <- create and update permission
    -> : 设置字段读权限
    ->:false no read permission
  • : 忽略当前字段
    - no read/write permission,
    -:migration no migrate permission,
    -: all no read/write/migrate permission
    comment :【迁移时】为字段添加注释

关于CRUD的使用记录(常用重点)

1.增 create

单条增

// -----------------------------插入单条记录---------------------------------
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}

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

user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数

// 创建记录并更新给出的字段
db.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")

批量增

// -----------------------------批量插入多条记录-----------------------------
//要有效地插入大量记录,请将一个 slice 传递给 Create 方法。 GORM 将生成单独一条SQL语句来插入所有数据,并回填主键的值,钩子方法也会被调用。
var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
db.Create(&users)

//使用 CreateInBatches 分批创建时,你可以指定每批的数量。
var users = []User{{name: "jinzhu_1"}, ...., {Name: "jinzhu_10000"}}
// 数量为 100
db.CreateInBatches(users, 100)

创建钩子hook

  • GORM 允许用户定义的钩子有 BeforeSave, BeforeCreate, AfterSave, AfterCreate 创建记录时将调用这些钩子方法。
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
  u.UUID = uuid.New()

    if u.Role == "admin" {
        return errors.New("invalid role")
    }
    return
}
// 如果想跳过 钩子 方法,可以使用 SkipHooks 会话模式
DB.Session(&gorm.Session{SkipHooks: true}).Create(&user)
DB.Session(&gorm.Session{SkipHooks: true}).Create(&users)
DB.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(users, 100)

支持map创建

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

// batch insert from `[]map[string]interface{}{}`
db.Model(&User{}).Create([]map[string]interface{}{
  {"Name": "jinzhu_1", "Age": 18},
  {"Name": "jinzhu_2", "Age": 20},
})

默认值处理

对于声明了默认值的字段,像 0、‘’、false 等零值是不会保存到数据库。需要使用指针类。

type User struct {
  gorm.Model
  Name string         `gorm:"default:xiaoming"`
  Age  *int           `gorm:"default:18"`
  Active sql.NullBool `gorm:"default:true"`
}

type User struct {
  ID        string `gorm:"default:uuid_generate_v3()"` // db func
  FirstName string
  LastName  string
  Age       uint8
  FullName  string `gorm:"->;type:GENERATED ALWAYS AS (concat(firstname,' ',lastname));default:(-);"`
}

2.查 retrieve

查询指定记录

  • gorm提供了First()、Take()、Last()方法,以便从数据库中检索单个对象,当查询数据库时它添加了LIMIT 1 条件,且没有找到记录时,它会返回ErrRecordNotFound错误。
  • 如果想避免ErrRecordNotFound错误,可以使用Find()方法,比如db.Limit(1).Find(&user),Find()方法可以接受struct结构体和切片slice的数据。
//获取第一条记录(主键升序),只有在目标struct是指针或者通过db.Model()指定model时,该方法才有效
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;

result:=db.First(&user)
result.RowsAffected //找到返回的记录数
result.Error //return error or nil

//检查ErrRecordNotFound错误
errors.Is(result.Error,gorm.ErrRecordNotFound)

主键索引查询

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

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

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

db.First(&user,"id=?","123456")
SELECT * FROM users WHERE id="123456"


查询全部记录

//得到全部记录
result:=db.Find(&user)
SELECT * FROM users;

查询钩子hook

func(u *User) AfterFind(tx *gorm.DB)(err error){
if u.MemberShip ==""{
u.MemberShip="user"
}
return
}

条件查询(**重重重点!!!!)

  • 查询条件是string字符串
//查询正序第一条条件匹配记录
db.Where("name = ?","zhangsan").First(&user)
SELECT * FROM users WHERE name='zhangsan' ORDER BY id LIMIT 1;

//查询能满足条件匹配的所有记录
db.Where("name <> ?","zhangsan").Find(&user)
SELECT * FROM users WHERE name <> 'zhangsan';

//in用法 查询名字为张三,张三1的所有记录
db.Where("name IN ?",[]string{"zhangsan","zhangsan1"}).Find(&user)
SELECT * FROM users WHERE name IN ('zhangsan','zhangsan1');

//like用法 根据zhang姓模糊查询
db.Where("name LIKE ?","%zhang%").Find(&user)
SELECT * FROM users WHERE name LIKE '%zhang%';

//and用法
db.Where("name = ? AND age >= ?","zhngsan","20").Find(&user)
SELECT * FROM users WHERE name='zhangsan' AND age >=20;

//DateTime用法
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(&user)
SELECT * FROM user WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

  • 筛选特定字段
//筛选name和age字段
db.Select("name","age").Find(&user)
SELECT name,age FROM user;
db.Select([]string{"name","age"}).Find(&user)
SELECT name,age FROM user;

//sql函数使用
db.Table("users").Select("COALESCE(age,?)",42).Rows()
SELECT COALESCE(age,'42') FROM users;
  • 查询条件是struct 和 map
//struct 
db.Where(&User{Name:"zhangsan",Age:20}).First(&user)
SELECT * FROM users WHERE name="zhangsan" AND age=20 ORDER BY id LIMIT 1;

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

//传入主键切片
db.Where([]int64{1,2,3}).Find(&user)
SELECT * FROM users WHERE id IN(1,2,3);

  • 内联条件
// 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';

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

//
db.Find(&users,"name <> ? AND age > ?","bbQ",20)
SELECT * FROM users WHERE name <> "bbQ" 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条件
db.Not("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;

// Not In
db.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&users)
// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");

// Struct
db.Not(User{Name: "jinzhu", Age: 18}).First(&user)
// SELECT * FROM users WHERE name <> "jinzhu" AND age <> 18 ORDER BY id LIMIT 1;

// Not In slice of primary keys
db.Not([]int64{1,2,3}).First(&user)
// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;
  • Or条件
db.Where("role = ?","admin").Or("role = ?","super_admin").Find(&users)
SELECT * FROM users WHERE role='admin' OR role='super_admin';

//struct
db.Where("name='zhangsan'").Or(User{Name:"zhangsan",Age:18}).Find(&users)
SELECT * FROM users WHERE name='zhangsan' OR (name='zhangsan' AND age=18);

//map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2", "age": 18}).Find(&users)
SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

  • Order排序
db.Order("age desc,name").Find(&users)
SELECT * FROM users ORDER BY age DESC,name;

db.Order("age desc").Order("name").Find(&users)
SELECT * FROM users ORDER BY age DESC,name;

db.Clauses(clause.OrderBy{
  Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
}).Find(&User{})
SELECT * FROM users ORDER BY FIELD(id,1,2,3)
  • Limit 和 offset
db.Limit(3).Find(&users)
SELECT * FROM users Limits 3;

db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
SELECT * FROM users Limit 10;(users1)
SELECT * FROM users ;(users2)

db.Offset(3).Find(&users)
SELECT * FROM users OFFSET 3;

//分页第五页取十条记录
db.Limit(10).Offset(5).Find(&users)
SELECT * FROM users OFFSET 5 LIMIT 10;
//

  • group by 和 having
db.Model(&User{}).Select("name,sum(age) as total").Where("name LIKE ?","group%").Group("name").First(&result)
SELECT name,sum(age) as total FROM users WHERE name like "group%" GROUP BY name Limit 1;

db.Model(&User{}).Select("name, sum(age) as total").Group("name").Having("name = ?", "group").Find(&result)
SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING name = "group"

  • distinct
db.Distinct("name", "age").Order("name, age desc").Find(&results)
  • scan
type Result struct{
Name string
Age int
}
var result Result
db.Table("users").Select("name", "age").Where("name = ?", "Antonio").Scan(&result)

// Raw SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)

3.改 update

  • 更新指定记录
//-----------------------------保存所有字段-------------------------
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;

//-----------------------------更新单个列-------------------------
// 条件更新
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 的 ID 是 `111`
db.Model(&user).Update("name", "hello")
UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

// 根据条件和 model 的值进行更新
db.Model(&user).Where("active = ?", true).Update("name", "hello")
UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

//-----------------------------更新多列-------------------------
// 根据 `struct` 更新属性,只会更新非零值的字段
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;

// 根据 `map` 更新属性
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

//-----------------------------更新选定字段-------------------------
// 使用 Map 进行 Select
// User's ID is `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, updated_at='2013-11-17 21:34:10' WHERE id=111;

// 使用 Struct 进行 Select(会 select 零值的字段)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
UPDATE users SET name='new_name', age=0 WHERE id=111;

// Select 所有字段(查询包括零值字段的所有字段)
db.Model(&user).Select("*").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

// Select 除 Role 外的所有字段(包括零值字段的所有字段)
db.Model(&user).Select("*").Omit("Role").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

  • 批量更新
//-----------------------------批量更新-------------------------
// 根据 struct 更新
db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin';

// 根据 map 更新
db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);

//-----------------------------禁止全局更新-------------------------
//如果在没有任何条件的情况下执行批量更新,默认情况下,GORM 不会执行该操作,并返回 ErrMissingWhereClause 错误。对此,必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate 模式
db.Model(&User{}).Update("name", "jinzhu").Error // gorm.ErrMissingWhereClause

db.Model(&User{}).Where("1 = 1").Update("name", "jinzhu")
// UPDATE users SET `name` = "jinzhu" WHERE 1=1

db.Exec("UPDATE users SET name = ?", "jinzhu")
// UPDATE users SET name = "jinzhu"

db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("name", "jinzhu")
// UPDATE users SET `name` = "jinzhu"

//-----------------------------更新记录数-------------------------
// 通过 `RowsAffected` 得到更新的记录数
result := db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin';

result.RowsAffected // 更新的记录数
result.Error        // 更新的错误

  • 更新钩子hook
//-----------------------------更新 Hook-------------------------
//GORM 支持 BeforeSave、BeforeUpdate、AfterSave、AfterUpdate 钩子,这些方法将在更新记录时被调用
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
    if u.Role == "admin" {
        return errors.New("admin user not allowed to update")
    }
    return
}

4.删 delete

  • 删除指定记录
//-----------------------------删除一条记录-------------------------
//删除一条记录时,删除对象需要指定主键,否则会触发 批量 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";

//-----------------------------根据主键删除-------------------------
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%";

//-----------------------------禁止全局删除-------------------------
//如果在没有任何条件的情况下执行批量删除,GORM 不会执行该操作,并返回 ErrMissingWhereClause 错误。对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate 模式
db.Delete(&User{}).Error // gorm.ErrMissingWhereClause

db.Where("1 = 1").Delete(&User{})
// DELETE FROM `users` WHERE 1=1

db.Exec("DELETE FROM users")
// DELETE FROM users

db.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})
// DELETE FROM users
  • 软删除
    如果model包含gorm.deletedat 字段(gorm.Model 已经包含了该字段),它将自动获得软删除的能力!拥有软删除能力的模型调用 Delete 时,记录不会从数据库中被真正删除。但 GORM 会将 DeletedAt 置为当前时间,并且不能再通过普通的查询方法找到该记录。
//-----------------------------软删除-------------------------
//By default, gorm.Model uses *time.Time as the value for the DeletedAt field, and it provides other data formats support with plugin gorm.io/plugin/soft_delete
import "gorm.io/plugin/soft_delete"
type User struct {
  ID        uint
  Name      string                `gorm:"uniqueIndex:udx_name"`
  DeletedAt soft_delete.DeletedAt `gorm:"uniqueIndex:udx_name"`
  // DeletedAt soft_delete.DeletedAt `gorm:"softDelete:nano"`
  //IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
}

// Query
SELECT * FROM users WHERE is_del = 0;

// Delete
UPDATE users SET is_del = 1 WHERE ID = 1;

// user 的 ID 是 `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;

// 在查询时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

//-----------------------------查找被软删除的记录-------------------------
db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;

//-----------------------------永久删除-------------------------
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;

  • 删除钩子hook
//-----------------------------删除 Hook-------------------------
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
    if u.Role == "admin" {
        return errors.New("admin user not allowed to delete")
    }
    return
}

5.原生raw sql写法

type Result struct{
ID int 
Name string
Age int
}
var result Result
db.Raw("SELECT id,name,age From users WHERE name=?",3).Scan(&result)


var ages int 
db.Raw("SELECT SUM(age) FROM users WHERE role = ?","admin").Scan(&ages)

var users []User
db.Raw("UPDATE users SET name = ? WHERE age = ? RETURNING id,name","zhangsan",20).Scan(&users)

原生exec sql写法

db.Exec("DROP TABLE users")
db.Exec("UPDATE orders SET shipped_at = ? WHERE id IN ?",time.Now(),[]int64{1,2,3})

db.Exec("UPDATE users SET money = ? WHERE name =?",gorm.Expr("money * ? + ?",10000,1),"zhangsan")

row和rows

//获取 *sql.Row结果
//使用gorm api 构建sql
row :=db.Table("users").Where("name = ?","zhangsan").Select("name","age").Row()
row.Scan(&name,&age)

//使用原生sql
row:=db.Raw("SELECT  name ,age ,email FROM users WHERE name=?","zhangsan").Row()
row.Scan(&name,&age,&email)

rows,err:=db.Raw("SELECT name,age,email FROM users WHERE name=?","zhangsan").Rows()
defer rows.Close()
for rows.Next(){
rows.Scan(&name,&age,&email)
//crud
}

//
rows,err:=db.Model(&User{}).Where("name = ?","zhangsan").Select("name,age,email").Rows()
defer rows.Close()
var user User
for rows.Next(){
//ScanRows 将一行扫描至user
db.ScanRows(rows,&user)
//crud
}

你可能感兴趣的:(Golang基础,golang)