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
}

相关内容

热门资讯

原创 真... 乔布斯曾讲过一个企业的底层逻辑:如果你在顶层做了正确的事,底层的结果就会随之而来。 人们关注企业每年...
国内成品油价今晚上涨,加满一箱... 界面新闻记者 | 田鹤琪 国内成品油价迎来“三连涨”。 2月24日,国家发改委发布消息称,自24时...
马斯克设想从月球电磁弹射AI卫... IT之家 2 月 25 日消息,据新华社报道,为更便捷部署专用于人工智能 (AI) 的数据中心卫星网...
马年首涨:中概股破局,A股引领... 在黄金因美元强势而黯然跳水、A股于春节后首个交易日释放出久违的磅礴巨量之际,大洋彼岸的美股市场,第一...
原创 帮... 昨晚大宗商品市场,走出一场“分道扬镳”的戏码。 原油连续第三天下跌,WTI跌破66美元,布伦特收在7...
今起可预约!办理2025年度个... 今起可预约!办理2025年度个税汇算 这些事项要注意 2026-02-25 06:54:50 看看...
原创 天... 年后的天津二手房,马上就要起跑了。 其实在1月份迹象就已显现。 往年的楼市淡季却“反常”得活跃:连续...
13F机构追踪:谷歌、拼多多、... 来源:活报告 在美股市场,资产管理规模超过1亿美元的机构需要在每个季度结束后的45天内向SEC提交1...
原创 手... 最近一段时间,有个词突然走红甚至冲上热搜,这就是手搓经济,在这个早已经现代工业化的时代,手搓经济是怎...
【美联储理事警告:美联储货币政... 【美联储理事警告:美联储货币政策可能无法应对AI引发的失业潮 】库克称,AI已引发美国劳动力市场的代...
黄金和交易提醒:金价高位“吞没... 来源:市场资讯 文章来源:汇通财经 周三(2月26日)亚市早盘,现货黄金窄幅震荡,目前交投于5150...
IPO雷达| 百普赛斯港股IP... 百普赛斯(301080.SZ)正式向香港联交所递交招股书。根据公司同步发布的2025年度业绩预告,全...
原创 澳... 2025年一则“澳洲高薪挖角中国稀土团队”的新闻,把全球稀土市场搅得风生水起。澳大利亚莱纳斯公司甩出...
苹果收购单人AI初创公司inv... IT之家 2 月 25 日消息,据 MacRumors 报道,一份提交给欧盟的新文件显示,苹果公司已...
珍惜:由早晨跑步所想到的 我每天早晨起来习惯在校园跑步,在跑步的时候,常常会思考跑步、人生及享受人生之间的关系。 我们知道人的...
趁乱抛售?最高法院刚裁决,对冲... 来源:市场资讯 来源:金十数据 根据外媒获得的一份美国银行报告,花旗的对冲基金客户在上周五美国最高法...
特别关注|9艘!“超高规格”新... 根据广船国际官微介绍,上述MR型油轮新造船为广船国际自主设计,总长约183米、宽32.2米,设计服务...
甲骨文股价在星门项目相关报道发... 来源:环球市场播报 周一, 甲骨文股价下跌4.5%,此前报道称,这家云计算公司与OpenAI和软银的...