GORM使用笔记
admin
2024-03-29 05:19:03
0

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 modelsimport ("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.DBtype 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 errorvar 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 = dbcasbin.InitCasbin(db)}
// addExtraSpaceIfExist adds a separator
func addExtraSpaceIfExist(str string) string {if str != "" {return " " + str}return ""
}
package conftype 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.TimeUpdatedAt time.TimeDeletedAt 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.ModelName 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 funcFirstName stringLastName  stringAge       uint8FullName  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.ErrMissingWhereClausedb.Model(&User{}).Where("1 = 1").Update("name", "jinzhu")
// UPDATE users SET `name` = "jinzhu" WHERE 1=1db.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.ErrMissingWhereClausedb.Where("1 = 1").Delete(&User{})
// DELETE FROM `users` WHERE 1=1db.Exec("DELETE FROM users")
// DELETE FROM usersdb.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        uintName      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
}

相关内容

热门资讯

贷款也“拼团” 银行抢单忙 购物能“拼团”,贷款也能! 近日,一场“拼团融资”的银企对接活动在省工业和信息化厅拉开帷幕。 “贷款...
逛花展、赶市集、嗨直播!202... 5月23日 “2026北京直播电商购物月” 在丰台区丽泽金融商务区·2026北京国际花展 正式拉开帷...
2026中关村毕业季|AI“吃... “上帝会掷骰子吗?” 在联想未来中心的“与智者同场”展区,一位海淀学子对着屏幕问道。 爱因斯坦微微前...
原创 今... 今日为5月23日,国际现货黄金价格在4500美元/盎司整数关口附近徘徊不前,日内最低触及4480美元...
三连亏后变为“无主”状态,农尚... 从吴亮手中接盘农尚环境(300536)不足三年后,林峰如今让出了公司控制权,上市公司进入“无主”状态...
55岁湖南女首富出手!豪掷13... 快科技5月24日消息,与马斯克、库克并肩而坐,刚参加完国宴的湖南女首富周群飞就买了家上市企业。 近日...
外资加仓A股,岂是跟风这么简单... 熬过忙碌的交易日,在周末安静时段,理清接下来布局方向。本篇为大家准备了5条要闻,涵盖市场动态、行业变...
原创 俄... 在全球能源的残酷牌桌上,手里攥着石油,腰杆子才能硬气。长期以来,中东的沙漠、俄罗斯的冰原、美国的页岩...
喜力啤酒有产品将涨价,华润啤酒... 来源:红星新闻 红星资本局5月22日消息,今日,红星资本局从雪花啤酒(厦门)有限公司、华润啤酒方面获...
原创 金... 心理预期调整刻不容缓,五月二十二日,黄金价格或将重现十五年前的历史性低迷。 近期若您密切关注着黄金市...
原创 马... 埃隆·马斯克如果能让SpaceX实现“科幻小说”级别的目标,他可能获得1万亿美元的收入。 埃隆·马斯...
涨涨涨!放开限制、可加杠杆!这... 韩国股市站在风口上! 据最新消息,为吸引更多海外资金进入股市,韩国政府计划放开限制,允许境外投资者直...
下周9家上会丨科创板首单IPO... IPO及再融资上会预告 据交易所官网审核动态信息,下周(5.25-5.29)IPO上会审核6家企业,...
富途、老虎市值蒸发1/4!或被... 来源:金融时报 5月22日,中国证监会宣布依法对Tiger Brokers (NZ) Limited...
马爸爸的好兄弟钱多多搞了杀猪盘... *此图由AI生成 作者| 史大郎&猫哥 来源| 是史大郎&大猫财经Pro 上周四,港股经纬天地大崩盘...
原创 壳... 编辑:XL 国际能源圈最近炸开了锅,壳牌这家百年石油巨头在2026年3月与委内瑞拉政府正式签署多项油...
存储热潮愈演愈烈!奖金拿到手软... 财联社5月24日讯(编辑 卞纯)在席卷全球的存储芯片热潮中,韩国“存储芯片双雄”SK海力士和三星无疑...
揽牌、合作、生态,跨境支付头部... 近日,国内头部跨境支付机构密集落地海外重要布局,一方面,连连数字、PingPong两家公司相继在中东...
原创 帮... 老铁们,周末好!我是帮主郑重。刚扫了一眼下周的财经日历,好家伙,事件一个接一个,堪称“消息面轰炸周”...
海南省住建厅与中国石化海南石油... 5月22日,中国石化海南石油分公司代表、党委书记李新强、总经理蔡文东一行赴海南省住建厅拜访交流。省住...