具体操作完成

main
han-joker 1 year ago
parent 884bdd6f84
commit b0a545a6d8

@ -0,0 +1,16 @@
package gormExample
import (
"context"
"fmt"
"log"
)
func ContextTimeoutCancel(ctx context.Context) {
// 传递Context执行
var cs []Content
if err := DB.WithContext(ctx).Limit(5).Find(&cs).Error; err != nil {
log.Fatalln(err)
}
fmt.Println(cs)
}

@ -0,0 +1,15 @@
package gormExample
import (
"context"
"testing"
"time"
)
func TestContextTimeoutCancel(t *testing.T) {
// 设置一个定时Cancel的Context
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
ContextTimeoutCancel(ctx)
}

@ -0,0 +1,45 @@
package gormExample
import (
"fmt"
"log"
)
func DeleteWhere() {
result1 := DB.Delete(&Content{}, "likes < ?", 100)
if result1.Error != nil {
log.Fatalln(result1.Error)
}
//[9.643ms] [rows:0] UPDATE `msb_content` SET `deleted_at`='2023-04-21 19:11:47.799' WHERE likes < 100 AND `msb_content`.`deleted_at` IS NULL
result2 := DB.Where("likes < ?", 100).Delete(&Content{})
if result2.Error != nil {
log.Fatalln(result2.Error)
}
//[5.928ms] [rows:0] UPDATE `msb_content` SET `deleted_at`='2023-04-21 19:11:47.807' WHERE likes < 100 AND `msb_content`.`deleted_at` IS NULL
}
func FindDeleted() {
var c Content
DB.Delete(&c, 13)
if err := DB.First(&c, 13).Error; err != nil {
log.Println(err)
}
//[4.604ms] [rows:0] SELECT * FROM `msb_content` WHERE `msb_content`.`id` = 13 AND `msb_content`.`deleted_at` IS NULL ORDER BY `msb_content`.`id` LIMIT 1
if err := DB.Unscoped().First(&c, 13).Error; err != nil {
log.Println(err)
}
// [3.320ms] [rows:1] SELECT * FROM `msb_content` WHERE `msb_content`.`id` = 13 ORDER BY `msb_content`.`id` LIMIT 1
fmt.Printf("%+v\n", c)
}
func DeleteHard() {
var c Content
if err := DB.Unscoped().Delete(&c, 14).Error; err != nil {
log.Fatalln(err)
}
// [8.135ms] [rows:0] DELETE FROM `msb_content` WHERE `msb_content`.`id` = 14
}

@ -0,0 +1,15 @@
package gormExample
import "testing"
func TestDeleteWhere(t *testing.T) {
DeleteWhere()
}
func TestFindDeleted(t *testing.T) {
FindDeleted()
}
func TestDeleteHard(t *testing.T) {
DeleteHard()
}

@ -304,7 +304,3 @@ type BlogBasic struct {
Summary string
Content string
}
type Author struct {
Name string
Emaile string
}

@ -0,0 +1,83 @@
package gormExample
import (
"gorm.io/gorm"
"gorm.io/gorm/clause"
"log"
"time"
)
type Content struct {
gorm.Model
Subject string
Likes uint `gorm:""`
Views uint `gorm:""`
//Likes uint `gorm:"default:99"`
//Views *uint `gorm:"default:99"`
PublishTime *time.Time
// 不需要迁移
// 禁用写操作
Sv string `gorm:"-:migration;<-:false"`
// 作者ID
AuthorID uint
}
// Author模型
type Author struct {
gorm.Model
Status int
Name string
Email string
}
type ContentStrPK struct {
ID string `gorm:"primaryKey"`
Subject string
Likes uint
Views uint
PublishTime *time.Time
}
const (
defaultViews = 99
defaultLikes = 99
)
func NewContent() Content {
return Content{
Likes: defaultLikes,
Views: defaultViews,
}
}
// Hook
func (c *Content) BeforeCreate(db *gorm.DB) error {
// 业务
if c.PublishTime == nil {
now := time.Now()
c.PublishTime = &now
}
// 配置
db.Statement.AddClause(clause.OnConflict{UpdateAll: true})
log.Println("content before create hook")
return nil
}
func (c *Content) AfterCreate(db *gorm.DB) error {
//return errors.New("custom error")
return nil
}
func (c *Content) AfterFind(db *gorm.DB) error {
if c.AuthorID == 0 {
c.AuthorID = 1 // 1 假定的默认作者
}
return nil
}

@ -1 +1,235 @@
package gormExample
import (
"fmt"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"log"
"time"
)
type User struct {
gorm.Model
Username string
Name string
Email string
Birthday *time.Time
}
func OperatorType() {
DB.AutoMigrate(&User{})
var users []User
// 一步操作
err := DB.
Order("name DESC").
Where("email like ?", "@163.com%").
Where("birthday IS NOT NULL").
Find(&users).Error // select all
if err != nil {
log.Fatal(err)
}
// 分步操作
query := DB.Where("birthday IS NOT NULL")
query = query.Where("email like ?", "@163.com%")
query = query.Order("name DESC")
query.Find(&users)
}
func CreateBasic() {
DB.AutoMigrate(&Content{})
// 模型映射记录,操作模型字段,就是操作记录的列
c1 := Content{}
c1.Subject = "GORM的使用"
// 执行创建insert
result1 := DB.Create(&c1)
// 处理错误
if result1.Error != nil {
log.Fatal(result1.Error)
}
// 最新的ID和影响的记录数
fmt.Println(c1.ID, result1.RowsAffected)
// map 指定数据
//设置map 的values
values := map[string]any{
"Subject": "Map指定值",
"PublishTime": time.Now(),
}
// create
result2 := DB.Model(&Content{}).Create(values)
if result2.Error != nil {
log.Fatal(result2.Error)
}
// 测试输出
fmt.Println(result2.RowsAffected)
}
func CreateMulti() {
DB.AutoMigrate(&Content{})
// 定义模型的切片
models := []Content{
{Subject: "标题1"},
{Subject: "标题2"},
{Subject: "标题3"},
}
// create 插入
result := DB.Create(&models)
if result.Error != nil {
log.Fatal(result.Error)
}
fmt.Println("RowsAffected:", result.RowsAffected)
for _, m := range models {
fmt.Println("ID:", m.ID)
}
// 切片结构同样支持
vs := []map[string]any{
{"Subject": "标题4"},
{"Subject": "标题5"},
{"Subject": "标题6"},
}
result2 := DB.Model(&Content{}).Create(vs)
if result2.Error != nil {
log.Fatal(result2.Error)
}
fmt.Println("RowsAffected:", result2.RowsAffected)
}
func CreateBatch() {
DB.AutoMigrate(&Content{})
// 定义模型的切片
models := []Content{
{Subject: "标题1"},
{Subject: "标题2"},
{Subject: "标题3"},
}
// create 插入
result := DB.CreateInBatches(&models, 2)
if result.Error != nil {
log.Fatal(result.Error)
}
fmt.Println("RowsAffected:", result.RowsAffected)
for _, m := range models {
fmt.Println("ID:", m.ID)
}
// 切片结构同样支持
vs := []map[string]any{
{"Subject": "标题4"},
{"Subject": "标题5"},
{"Subject": "标题6"},
}
result2 := DB.Model(&Content{}).CreateInBatches(vs, 2)
if result2.Error != nil {
log.Fatal(result2.Error)
}
fmt.Println("RowsAffected:", result2.RowsAffected)
}
func UpSert() {
DB.AutoMigrate(&Content{})
// 常规插入,原始数据
c1 := Content{}
c1.Subject = "原始标题"
c1.Likes = 10
DB.Create(&c1)
fmt.Println(c1)
// 主键冲突的错误
//c2 := Content{}
//c2.ID = c1.ID
//c2.Subject = "新标题"
//c2.Likes = 20
//if err := DB.Create(&c2).Error; err != nil {
// log.Fatal(err)
// // Error 1062 (23000): Duplicate entry '17' for key 'msb_content.PRIMARY'
//}
// 冲突后,更新全部字段
//c3 := Content{}
//c3.ID = c1.ID
//c3.Subject = "新标题"
//c3.Likes = 20
//if err := DB.
// Clauses(clause.OnConflict{
// UpdateAll: true,
// }).
// Create(&c3).Error; err != nil {
// log.Fatal(err)
//}
// 冲突后,更新部分字段
c4 := Content{}
c4.ID = c1.ID
c4.Subject = "新标题"
c4.Likes = 20
if err := DB.
Clauses(clause.OnConflict{
DoUpdates: clause.AssignmentColumns([]string{"likes"}),
}).
Create(&c4).Error; err != nil {
log.Fatal(err)
}
}
func DefaultValue() {
DB.AutoMigrate(&Content{})
// 常规插入,原始数据
c1 := Content{}
c1.Subject = "原始标题"
c1.Likes = 0
//views := uint(0)
//c1.Views = &views
DB.Create(&c1)
//fmt.Println(c1.Likes, *c1.Views)
}
func DefaultValueOften() {
DB.AutoMigrate(&Content{})
c1 := NewContent()
c1.Subject = "原始标题"
DB.Create(&c1)
fmt.Println(c1.Likes, c1.Views)
}
func SelectOmit() {
DB.AutoMigrate(&Content{})
c1 := Content{}
c1.Subject = "原始标题"
c1.Likes = 10
c1.Views = 99
now := time.Now()
c1.PublishTime = &now
//DB.Select("Subject", "Likes", "UpdatedAt").Create(&c1)
//INSERT INTO `msb_content` (`created_at`,`updated_at`,`subject`,`likes`) VALUES ('2023-04-11 18:11:26.384','2023-04-11 18:11:26.384','原始标题',10)
DB.Omit("Subject", "Likes", "UpdatedAt").Create(&c1)
//INSERT INTO `msb_content` (`created_at`,`deleted_at`,`views`,`publish_time`) VALUES ('2023-04-11 18:12:39.431',NULL,99,'2023-04-11 18:12:39.429')
}
func CreateHook() {
DB.AutoMigrate(&Content{})
c1 := Content{}
err := DB.Create(&c1).Error
if err != nil {
log.Fatal(err)
}
//INSERT INTO `msb_content` (`created_at`,`updated_at`,`deleted_at`,`subject`,`likes`,`views`,`publish_time`) VALUES ('2023-04-11 18:44:56.62','2023-04-11 18:44:56.62',NULL,'',0,0,'2023-04-11 18:44:56.62') ON DUPLICATE KEY UPDATE `updated_at`='2023-04-11 18:44:56.62',`deleted_at`=VALUES(`deleted_at`),`subject`=VALUES(`subject`),`likes`=VALUES(`likes`),`views`=VALUES(`views`),`publish_time`=VALUES(`publish_time`)
}

@ -1 +1,35 @@
package gormExample
import "testing"
func TestOperatorType(t *testing.T) {
OperatorType()
}
func TestCreateBasic(t *testing.T) {
CreateBasic()
}
func TestCreateMulti(t *testing.T) {
CreateMulti()
}
func TestCreateBatch(t *testing.T) {
CreateBatch()
}
func TestUpSert(t *testing.T) {
UpSert()
}
func TestDefaultValue(t *testing.T) {
DefaultValue()
}
func TestSelectOmit(t *testing.T) {
SelectOmit()
}
func TestCreateHook(t *testing.T) {
CreateHook()
}

@ -0,0 +1,75 @@
package gormExample
import "log"
// 原生查询测试
func RawSelect() {
// 结果类型
type Result struct {
ID uint
Subject string
Likes, Views int
}
var rs []Result
// SQL
sql := "SELECT `id`, `subject`, `likes`, `views` FROM `msb_content` WHERE `likes` > ? ORDER BY `likes` DESC LIMIT ?"
// 执行SQL并扫描结果
if err := DB.Raw(sql, 99, 12).Scan(&rs).Error; err != nil {
log.Fatalln(err)
}
// [8.298ms] [rows:12] SELECT `id`, `subject`, `likes`, `views` FROM `msb_content` WHERE `likes` > 99 ORDER BY `likes` DESC LIMIT 12
log.Println(rs)
}
// 执行类的SQL原生
func RawExec() {
// SQL
sql := "UPDATE `msb_content` SET `subject` = CONCAT(`subject`, '-new postfix') WHERE `id` BETWEEN ? AND ?"
// 执行,获取结果
result := DB.Exec(sql, 30, 40)
if result.Error != nil {
log.Fatalln(result.Error)
}
// [13.369ms] [rows:10] UPDATE `msb_content` SET `subject` = CONCAT(`subject`, '-new postfix') WHERE `id` BETWEEN 30 AND 40
log.Println(result.RowsAffected)
}
// sql.Row 或 sql.Rows 类型的结果处理
func RowAndRows() {
// sql
sql := "SELECT `id`, `subject`, `likes`, `views` FROM `msb_content` WHERE `likes` > ? ORDER BY `likes` DESC LIMIT ?"
// 执行获取rows
rows, err := DB.Raw(sql, 99, 12).Rows()
if err != nil {
log.Fatalln(err)
}
// 遍历rows
for rows.Next() {
// 扫描的列独立的变量
//var id uint
//var subject string
//var likes, views int
//rows.Scan(&id, &subject, &likes, &views)
//log.Println(id, subject, likes, views)
// 扫描到整体结构体
type Result struct {
ID uint
Subject string
Likes, Views int
}
var r Result
if err := DB.ScanRows(rows, &r); err != nil {
log.Fatalln(err)
}
log.Println(r)
}
}

@ -0,0 +1,15 @@
package gormExample
import "testing"
func TestRawSelect(t *testing.T) {
RawSelect()
}
func TestRawExec(t *testing.T) {
RawExec()
}
func TestRowAndRows(t *testing.T) {
RowAndRows()
}

@ -0,0 +1,507 @@
package gormExample
import (
"database/sql"
"fmt"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"log"
"time"
)
func GetByPk() {
// migrate
DB.AutoMigrate(&Content{}, &ContentStrPK{})
// 查询单条
////c := Content{}
////if err := DB.First(&c, 10).Error; err != nil {
//// log.Println(err)
////}
//c := Content{}
//c.ID = 10
//if err := DB.First(&c).Error; err != nil {
// log.Println(err)
//}
//// 字符串类型的主键
//cStr := ContentStrPK{}
//if err := DB.First(&cStr, "id = ?", "some pk").Error; err != nil {
// //if err := DB.First(&cStr, "some pk").Error; err != nil {
// log.Println(err)
//}
//
//// 查询多条
//var cs []Content
//if err := DB.Find(&cs, []uint{10, 11, 12}).Error; err != nil {
// log.Println(err)
//}
// 字符串类型的主键
var cStrs []ContentStrPK
if err := DB.Find(&cStrs, []string{"some", "pk", "item"}).Error; err != nil {
log.Println(err)
}
}
func GetOne() {
c := Content{}
if err := DB.First(&c, "id > ?", 42).Error; err != nil {
log.Println(err)
}
o := Content{}
if err := DB.Last(&o, "id > ?", 42).Error; err != nil {
log.Println(err)
}
n := Content{}
if err := DB.Take(&n, "id > ?", 42).Error; err != nil {
log.Println(err)
}
f := Content{}
if err := DB.Limit(1).Find(&f, "id > ?", 42).Error; err != nil {
log.Println(err)
}
fs := Content{}
if err := DB.Find(&fs, "id > ?", 42).Error; err != nil {
log.Println(err)
}
}
func GetToMap() {
// 单条
c := map[string]any{} //map[string]interface{}{}
if err := DB.Model(&Content{}).First(&c, 13).Error; err != nil {
log.Println(err)
}
//fmt.Println(c["id"], c["id"].(uint) == 13)
// 需要接口类型断言,才能继续处理
if c["id"].(uint) == 13 {
fmt.Println("id bingo")
}
// time类型的处理
fmt.Println(c["created_at"])
t, err := time.Parse("2006-01-02 15:04:05.000 -0700 CST", "2023-04-10 22:00:11.582 +0800 CST")
if err != nil {
log.Println(err)
}
if c["created_at"].(time.Time) == t {
fmt.Println("created_at bingo")
}
// 多条
var cs []map[string]any
if err := DB.Model(&Content{}).Find(&cs, []uint{13, 14, 15}).Error; err != nil {
log.Println(err)
}
for _, c := range cs {
fmt.Println(c["id"].(uint), c["subject"].(string), c["created_at"].(time.Time))
}
}
func GetPluck() {
// 使用切片存储
var subjects []sql.NullString
//var subjects []string
if err := DB.Model(&Content{}).Pluck("subject", &subjects).Error; err != nil {
log.Println(err)
}
for _, subject := range subjects {
//NullString的使用
if subject.Valid {
fmt.Println(subject.String)
} else {
fmt.Println("[NULL]")
}
//
//fmt.Println(subject)
}
}
func GetPluckExp() {
// 使用切片存储如果表达式可以保证NULL不会出现了就可以不适用NullType了
var subjects []string
// 字段为表达式的结果
if err := DB.Model(&Content{}).Pluck("concat(coalesce(subject, '[no subject]'), '-', likes)", &subjects).Error; err != nil {
log.Println(err)
}
for _, subject := range subjects {
fmt.Println(subject)
}
}
func GetSelect() {
var c Content
// 基本的字段名
//if err := DB.Select("subject", "likes").First(&c, 13).Error; err != nil {
// log.Fatalln(err)
//}
// 字段表达式
if err := DB.Select("subject", "likes", "concat(subject,'-', views) AS sv").First(&c, 13).Error; err != nil {
log.Fatalln(err)
}
fmt.Printf("%+v\n", c)
}
func GetDistinct() {
var cs []Content
// 基本的字段名
if err := DB.Distinct("*").Find(&cs).Error; err != nil {
log.Fatalln(err)
}
fmt.Printf("%+v\n", cs)
}
func WhereMethod() {
var cs []Content
// inline条件内联条件
//if err := DB.Find(&cs, "likes > ? AND subject like ?", 100, "gorm%").Error; err != nil {
// log.Fatalln(err)
//}
// SELECT * FROM `msb_content` WHERE (likes > 100 AND subject like 'gorm%') AND `msb_content`.`deleted_at` IS NULL
// Where,通常在动态拼凑条件时使用
//query := DB.Where("likes > ?", 100)
//subject := ""
//// 当前用户输出subject不为空字符串时才拼凑subject条件
//if subject != "" {
// query.Where("subject like ?", subject+"%")
//}
//if err := query.Find(&cs).Error; err != nil {
// log.Fatalln(err)
//}
// SELECT * FROM `msb_content` WHERE likes > 100 AND `msb_content`.`deleted_at` IS NULL
// OR 逻辑运算
//query := DB.Where("likes > ?", 100)
//subject := "gorm"
//// 当前用户输出subject不为空字符串时才拼凑subject条件
//if subject != "" {
// //query.Where("subject like ?", "subject"+"%")
// query.Or("subject like ?", subject+"%")
//}
//if err := query.Find(&cs).Error; err != nil {
// log.Fatalln(err)
//}
// SELECT * FROM `msb_content` WHERE (likes > 100 OR subject like 'gorm%') AND `msb_content`.`deleted_at` IS NULL
// Not 逻辑运算
query := DB.Where("likes > ?", 100)
subject := "gorm"
// 当前用户输出subject不为空字符串时才拼凑subject条件
if subject != "" {
//query.Not("subject like ?", subject+"%")
// SELECT * FROM `msb_content` WHERE likes > 100 AND NOT subject like 'gorm%' AND `msb_content`.`deleted_at` IS NULL
query = query.Or(DB.Not("subject like ?", subject+"%"))
// SELECT * FROM `msb_content` WHERE (likes > 100 OR NOT subject like 'gorm%') AND `msb_content`.`deleted_at` IS NULL
}
if err := query.Find(&cs).Error; err != nil {
log.Fatalln(err)
}
}
func WhereType() {
var cs []Content
// 嵌套分组构建复杂的逻辑运算
// (1 or 2) and (3 and (4 or 5))
// 1 or 2
//condA := DB.Where("likes > ?", 10).Or("likes <= ?", 100)
// 3 and (4 or 5)
//condB := DB.Where("views > ?", 20).Where(DB.Where("views <= ?", 200).Or("subject like ?", "gorm%"))
//query := DB.Where(condA).Where(condB)
// SELECT * FROM `msb_content` WHERE (likes > 10 OR likes <= 100) AND (views > 20 AND (views <= 200 OR subject like 'gorm%')) AND `msb_content`.`deleted_at` IS NULL
// map构建条件, and, = in
//query := DB.Where(map[string]any{
// "views": 100,
// "id": []uint{1, 2, 3, 4, 5},
//})
// SELECT * FROM `msb_content` WHERE `id` IN (1,2,3,4,5) AND `views` = 100 AND `msb_content`.`deleted_at` IS NULL
// struct条件构建, and, =
query := DB.Where(Content{
Views: 100,
Subject: "GORM",
})
// SELECT * FROM `msb_content` WHERE `msb_content`.`subject` = 'GORM' AND `msb_content`.`views` = 100 AND `msb_content`.`deleted_at` IS NULL
if err := query.Find(&cs).Error; err != nil {
log.Fatalln(err)
}
}
func PlaceHolder() {
var cs []Content
// 匿名
//query := DB.Where("likes = ? AND subject like ?", 100, "gorm%")
// 具名绑定名字sql.Named()结构
//query := DB.Where("likes = @like AND subject like @subject", sql.Named("subject", "gorm%"), sql.Named("like", 100))
// SELECT * FROM `msb_content` WHERE (likes = 100 AND subject like 'gorm%') AND `msb_content`.`deleted_at` IS NULL
// gorm还支持使用map的形式具名绑定
query := DB.Where("likes = @like AND subject like @subject", map[string]any{
"subject": "gorm%",
"like": 100,
})
// SELECT * FROM `msb_content` WHERE (likes = 100 AND subject like 'gorm%') AND `msb_content`.`deleted_at` IS NULL
if err := query.Find(&cs).Error; err != nil {
log.Fatalln(err)
}
}
func OrderBy() {
var cs []Content
ids := []uint{2, 3, 1}
//query := DB.Order("FIELD(id, 2, 3, 1)")
query := DB.Clauses(clause.OrderBy{
Expression: clause.Expr{
SQL: "FIELD(id, ?)",
Vars: []any{ids},
WithoutParentheses: true,
},
})
// SELECT * FROM `msb_content` WHERE `msb_content`.`id` IN (2,3,1) AND `msb_content`.`deleted_at` IS NULL ORDER BY FIELD(id, 2,3,1)
if err := query.Find(&cs, ids).Error; err != nil {
log.Fatalln(err)
}
for _, c := range cs {
fmt.Println(c.ID)
}
}
// 定义分页必要数据结构
type Pager struct {
Page, PageSize int
}
// 默认的值
const (
DefaultPage = 1
DefaultPageSize = 12
)
// 翻页程序
func Pagination(pager Pager) {
// 确定page, offset 和 pagesize
page := DefaultPage
if pager.Page != 0 {
page = pager.Page
}
pagesize := DefaultPageSize
if pager.PageSize != 0 {
pagesize = pager.PageSize
}
// 计算offset
// page, pagesize, offset
// 1, 10, 0
// 2, 10, 10
// 3, 10, 20
offset := pagesize * (page - 1)
var cs []Content
// SELECT * FROM `msb_content` WHERE `msb_content`.`deleted_at` IS NULL LIMIT 15 OFFSET 30
if err := DB.Offset(offset).Limit(pagesize).Find(&cs).Error; err != nil {
log.Fatalln(err)
}
}
// 用于得到func(db *gorm.DB) *gorm.DB类型函数
// 为什么不直接定义函数因为需要func(db *gorm.DB) *gorm.DB与分页信息产生联系。
func Paginate(pager Pager) func(db *gorm.DB) *gorm.DB {
// 计算page
page := DefaultPage
if pager.Page != 0 {
page = pager.Page
}
// 计算pagesize
pagesize := DefaultPageSize
if pager.PageSize != 0 {
pagesize = pager.PageSize
}
// 计算offset
// page, pagesize, offset
// 1, 10, 0
// 2, 10, 10
// 3, 10, 20
offset := pagesize * (page - 1)
return func(db *gorm.DB) *gorm.DB {
// 使用闭包的变量,实现翻页的业务逻辑
return db.Offset(offset).Limit(pagesize)
}
}
// 测试重用的分页查询
func PaginationScope(pager Pager) {
var cs []Content
// SELECT * FROM `msb_content` WHERE `msb_content`.`deleted_at` IS NULL LIMIT 15 OFFSET 30
if err := DB.Scopes(Paginate(pager)).Find(&cs).Error; err != nil {
log.Fatalln(err)
}
var ps []Post
// SELECT * FROM `msb_post` WHERE `msb_content`.`deleted_at` IS NULL LIMIT 15 OFFSET 30
if err := DB.Scopes(Paginate(pager)).Find(&ps).Error; err != nil {
log.Fatalln(err)
}
}
func Count(pager Pager) {
// 集中的条件,用于统计数量和获取某页记录
query := DB.Model(&Content{}).
Where("likes > ?", 99)
// total rows count
var count int64
if err := query.Count(&count).Error; err != nil {
log.Fatalln(err)
}
// SELECT count(*) FROM `msb_content` WHERE likes > 99 AND `msb_content`.`deleted_at` IS NULL
// 计算总页数 ceil( count / pagesize)
// rows per page
var cs []Content
if err := query.Scopes(Paginate(pager)).Find(&cs).Error; err != nil {
log.Fatalln(err)
}
// SELECT * FROM `msb_content` WHERE likes > 99 AND `msb_content`.`deleted_at` IS NULL LIMIT 15 OFFSET 30
}
func GroupHaving() {
DB.AutoMigrate(&Content{})
// 定义查询结构类型
type Result struct {
// 分组字段
AuthorID uint
// 合计字段
TotalViews int
TotalLikes int
AvgViews float64
}
// 执行分组合计过滤查询
var rs []Result
if err := DB.Model(&Content{}).
Select("author_id", "SUM(views) as total_views", "SUM(likes) as total_likes", "AVG(views) as avg_views").
Group("author_id").Having("total_views > ?", 99).
Find(&rs).Error; err != nil {
log.Fatalln(err)
}
// SQL
// SELECT `author_id`,SUM(views) as total_views,SUM(likes) as total_likes,AVG(views) as avg_views FROM `msb_content` WHERE `msb_content`.`deleted_at` IS NULL GROUP BY `author_id` HAVING total_views > 99
}
func Iterator() {
// 利用DB.Rows() 获取Rows对象
rows, err := DB.Model(&Content{}).Rows()
if err != nil {
log.Fatalln(err)
}
// [rows:-] SELECT * FROM `msb_content` WHERE `msb_content`.`deleted_at` IS NULL
// 注意保证使用过后关闭rows结果集
defer func() {
_ = rows.Close()
}()
fmt.Println(rows)
// 迭代的从Rows中扫描记录到模型
for rows.Next() {
// 还有记录存在与结果集中
var c Content
if err := DB.ScanRows(rows, &c); err != nil {
log.Fatalln(err)
}
fmt.Println(c.Subject)
}
}
func Locking() {
var cs []Content
if err := DB.
Clauses(clause.Locking{Strength: "UPDATE"}).
Find(&cs).Error; err != nil {
log.Fatalln(err)
}
// [4.998ms] [rows:42] SELECT * FROM `msb_content` WHERE `msb_content`.`deleted_at` IS NULL FOR UPDATE
if err := DB.
Clauses(clause.Locking{Strength: "SHARE"}).
Find(&cs).Error; err != nil {
log.Fatalln(err)
}
// [3.006ms] [rows:42] SELECT * FROM `msb_content` WHERE `msb_content`.`deleted_at` IS NULL FOR SHARE
}
func SubQuery() {
// migrate
DB.AutoMigrate(&Author{}, &Content{})
// 条件型子查询
//select * from content where author_id in (select id from author where status=0);
// 子查询不需要使用终结方法Find完成查询只需要构建语句即可
whereSubQuery := DB.Model(&Author{}).Select("id").Where("status = ?", 0)
var cs []Content
if err := DB.Where("author_id IN (?)", whereSubQuery).Find(&cs).Error; err != nil {
log.Fatalln(err)
}
// [4.782ms] [rows:0] SELECT * FROM `msb_content` WHERE author_id IN (SELECT `id` FROM `msb_author` WHERE status = 0 AND `msb_author`.`deleted_at` IS NULL) AND `msb_content`.`deleted_at` IS NULL
// from型子查询
//select * from (select subject, likes from content where publish_time is null) as temp where likes > 10;
fromSubQuery := DB.Model(&Content{}).Where("publish_time IS NULL").Select("subject", "likes")
type Result struct {
Subject string
Likes int
}
var rs []Result
if err := DB.Table("(?) AS temp", fromSubQuery).
Where("likes > ?", 10).
Find(&rs).Error; err != nil {
log.Fatalln(err)
}
// [3.800ms] [rows:17] SELECT * FROM (SELECT `subject`,`likes` FROM `msb_content` WHERE publish_time IS NULL AND `msb_content`.`deleted_at` IS NULL) AS temp WHERE likes > 10
}
func FindHook() {
var c Content
if err := DB.First(&c, 13).Error; err != nil {
log.Fatalln(err)
}
fmt.Printf("%+v\n", c)
}

@ -0,0 +1,82 @@
package gormExample
import "testing"
func TestGetByPk(t *testing.T) {
GetByPk()
}
func TestGetOne(t *testing.T) {
GetOne()
}
func TestGetToMap(t *testing.T) {
GetToMap()
}
func TestGetPluck(t *testing.T) {
GetPluck()
}
func TestGetPluckExp(t *testing.T) {
GetPluckExp()
}
func TestGetSelect(t *testing.T) {
GetSelect()
}
func TestGetDistinct(t *testing.T) {
GetDistinct()
}
func TestWhereMethod(t *testing.T) {
WhereMethod()
}
func TestWhereType(t *testing.T) {
WhereType()
}
func TestPlaceHolder(t *testing.T) {
PlaceHolder()
}
func TestOrderBy(t *testing.T) {
OrderBy()
}
func TestPagination(t *testing.T) {
request := Pager{3, 15}
Pagination(request) // offset:30, limit:15
}
func TestPaginationScope(t *testing.T) {
request := Pager{3, 15}
PaginationScope(request)
}
func TestCount(t *testing.T) {
request := Pager{3, 15}
Count(request)
}
func TestGroupHaving(t *testing.T) {
GroupHaving()
}
func TestIterator(t *testing.T) {
Iterator()
}
func TestLocking(t *testing.T) {
Locking()
}
func TestSubQuery(t *testing.T) {
SubQuery()
}
func TestFindHook(t *testing.T) {
FindHook()
}

@ -0,0 +1,133 @@
package gormExample
import (
"fmt"
"gorm.io/gorm"
"log"
)
func SessionIssue() {
// 连续控制条件
//db := DB.Model(&Content{}).Where("views > ?", 100)
//db.Where("likes > ?", 9)
//var cs []Content
//db.Find(&cs)
// [4.319ms] [rows:0] SELECT * FROM `msb_content` WHERE views > 100 AND likes > 9 AND `msb_content`.`deleted_at` IS NULL
// 连续执行查询
// 1
// Where("views > ?", 100).Where("likes > ?", 9)
db := DB.Model(&Content{}).Where("views > ?", 100)
db.Where("likes > ?", 9)
var cs1 []Content
db.Find(&cs1)
// [10.566ms] [rows:0] SELECT * FROM `msb_content` WHERE views > 100 AND likes > 9 AND `msb_content`.`deleted_at` IS NULL
// 2,找到likes<5
// Where("views > ?", 100).Where("likes < ?", 5)
db.Where("likes < ?", 5)
var cs2 []Content
db.Find(&cs2)
// [2.815ms] [rows:0] SELECT * FROM `msb_content` WHERE views > 100 AND likes > 9 AND `msb_content`.`deleted_at` IS NULL AND likes < 5
}
func SessionDB() {
// 连续执行查询
// 1
// Where("views > ?", 100).Where("likes > ?", 9)
db1 := DB.Model(&Content{}).Where("views > ?", 100)
db1.Where("likes > ?", 9)
var cs1 []Content
db1.Find(&cs1)
// [10.683ms] [rows:0] SELECT * FROM `msb_content` WHERE views > 100 AND likes > 9 AND `msb_content`.`deleted_at` IS NULL
// 2,找到likes<5
// Where("views > ?", 100).Where("likes < ?", 5)
db2 := DB.Model(&Content{}).Where("views > ?", 100)
db2.Where("likes < ?", 5)
var cs2 []Content
db2.Find(&cs2)
// [4.139ms] [rows:0] SELECT * FROM `msb_content` WHERE views > 100 AND likes < 5 AND `msb_content`.`deleted_at` IS NULL
}
func SessionNew() {
// 需要重复使用的部分
// 将Session方法前的配置记录到了当前的会话中
// 后边再次调用db的方法直到终结方法会保持会话中的子句选项
// 执行完终结方法后再次调用db的方法到终结方法可以重用会话中的子句选项。
db := DB.Model(&Content{}).Where("views > ?", 100).Session(&gorm.Session{})
// 连续执行查询
// 1
// Where("views > ?", 100).Where("likes > ?", 9)
var cs1 []Content
db.Where("likes > ?", 9).Find(&cs1)
// [4.633ms] [rows:0] SELECT * FROM `msb_content` WHERE views > 100 AND likes > 9 AND `msb_content`.`deleted_at` IS NULL
// 2,找到likes<5
// Where("views > ?", 100).Where("likes < ?", 5)
var cs2 []Content
db.Where("likes < ?", 5).Find(&cs2)
// [3.846ms] [rows:0] SELECT * FROM `msb_content` WHERE views > 100 AND likes < 5 AND `msb_content`.`deleted_at` IS NULL
}
func SessionOptions() {
// Skip Hook
//db := DB.Session(&gorm.Session{
// SkipHooks: true,
//})
//db.Save(&Content{Subject: "no create hook"})
// DryRun
//db := DB.Session(&gorm.Session{
// DryRun: true,
//})
//stmt := db.Save(&Content{}).Statement
//fmt.Println(stmt.SQL.String())
//// INSERT INTO `msb_content` (`created_at`,`updated_at`,`deleted_at`,`subject`,`likes`,`views`,`publish_time`,`author_id`) VALUES (?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE `updated_at`=?,`deleted_at`=VALUES(`deleted_at`),`subject`=VALUES(`subject`),`likes`=VALUES(`likes`),`views`=VALUES(`views`),`publish_time`=VALUES(`publish_time`),`author_id`=VALUES(`author_id`)
//fmt.Println(stmt.Vars)
//// [2023-04-24 17:25:47.827 +0800 CST 2023-04-24 17:25:47.827 +0800 CST {0001-01-01 00:00:00 +0000 UTC false} 0 0 2023-04-24 17:25:47.823908 +0800 CST 0 2023-04-24 17:25:47.827 +0800 CST]
// Debug
//DB.Debug().First()
// prepare 预编译,编译重用,编译独立
// SQL, 编译,绑定数据,执行
// 预编译,将编译的过程缓存起来,便于重用。
// 在执行结构相同的SQL时可以重用。
db := DB.Session(&gorm.Session{
PrepareStmt: true,
})
// 预编译管理对象
stmtManager, ok := db.ConnPool.(*gorm.PreparedStmtDB)
if !ok {
log.Fatalln("*gorm.PreparedStmtDB assert failed")
}
fmt.Println(stmtManager.PreparedSQL)
fmt.Println(stmtManager.Stmts)
var c1 Content
db.First(&c1, 13)
fmt.Println(stmtManager.PreparedSQL)
fmt.Println(stmtManager.Stmts)
// [SELECT * FROM `msb_content` WHERE `msb_content`.`id` = ? AND `msb_content`.`deleted_at` IS NULL ORDER BY `msb_content`.`id` LIMIT 1]
// map[SELECT * FROM `msb_content` WHERE `msb_content`.`id` = ? AND `msb_content`.`deleted_at` IS NULL ORDER BY `msb_content`.`id` LIMIT 1:0xc0001cd920]
var c2 Content
db.First(&c2, 14)
fmt.Println(stmtManager.PreparedSQL)
fmt.Println(stmtManager.Stmts)
// [SELECT * FROM `msb_content` WHERE `msb_content`.`id` = ? AND `msb_content`.`deleted_at` IS NULL ORDER BY `msb_content`.`id` LIMIT 1]
// map[SELECT * FROM `msb_content` WHERE `msb_content`.`id` = ? AND `msb_content`.`deleted_at` IS NULL ORDER BY `msb_content`.`id` LIMIT 1:0xc0001cd920]
var c3 []Content
db.Find(&c3, []uint{15, 16})
fmt.Println(stmtManager.PreparedSQL)
fmt.Println(stmtManager.Stmts)
// [SELECT * FROM `msb_content` WHERE `msb_content`.`id` = ? AND `msb_content`.`deleted_at` IS NULL ORDER BY `msb_content`.`id` LIMIT 1 SELECT * FROM `msb_content` WHERE `msb_content`.`id` IN (?,?) AND `msb_content`.`deleted_at` IS NULL]
// map[SELECT * FROM `msb_content` WHERE `msb_content`.`id` = ? AND `msb_content`.`deleted_at` IS NULL ORDER BY `msb_content`.`id` LIMIT 1:0xc0001cb920 SELECT * FROM `msb_content` WHERE `msb_content`.`id` IN (?,?) AND `msb_content`.`deleted_at` IS NULL:0xc0001cbe30]
}

@ -0,0 +1,19 @@
package gormExample
import "testing"
func TestSessionIssue(t *testing.T) {
SessionIssue()
}
func TestSessionDB(t *testing.T) {
SessionDB()
}
func TestSessionNew(t *testing.T) {
SessionNew()
}
func TestSessionOptions(t *testing.T) {
SessionOptions()
}

@ -0,0 +1,94 @@
package gormExample
import (
"fmt"
"gorm.io/gorm"
"log"
)
func UpdatePK() {
var c Content
// 无主键
if err := DB.Save(&c).Error; err != nil {
log.Fatalln(err)
}
// [12.300ms] [rows:1] INSERT INTO `msb_content` (`created_at`,`updated_at`,`deleted_at`,`subject`,`likes`,`views`,`publish_time`,`author_id`) VALUES ('2023-04-21 16:42:35.089','2023-04-21 16:42:35.089',NULL,'',0,0,'2023-04-21 16:42:35.089',0) ON DUPLICATE KEY UPDATE `updated_at`='2023-04-21 16:42:35.089',`deleted_at`=VALUES(`deleted_at`),`subject`=VALUES(`subject`),`likes`=VALUES(`likes`),`views`=VALUES(`views`),`publish_time`=VALUES(`publish_time`),`author_id`=VALUES(`author_id`)
fmt.Printf("%+v\n", c)
// 具有主键ID
if err := DB.Save(&c).Error; err != nil {
log.Fatalln(err)
}
// [9.316ms] [rows:1] UPDATE `msb_content` SET `created_at`='2023-04-21 16:45:22.294',`updated_at`='2023-04-21 16:45:22.306',`deleted_at`=NULL,`subject`='',`likes`=0,`views`=0,`publish_time`='2023-04-21 16:45:22.293',`author_id`=0 WHERE `msb_content`.`deleted_at` IS NULL AND `id` = 61
fmt.Printf("%+v\n", c)
}
func UpdateWhere() {
// 更新的字段值数据
// map推荐
values := map[string]any{
"subject": "Where Update Row",
"likes": 10001,
}
// 执行带有条件的更新
result := DB.Model(&Content{}).
//Omit("updated_at").
Where("likes > ?", 100).
Updates(values)
if result.Error != nil {
log.Fatalln(result.Error)
}
// 获取更新结果,更新的记录数量(受影响的记录数)
// 指的是修改的记录数,而不是满足条件的记录数
log.Println("updated rows num: ", result.RowsAffected)
}
func UpdateNoWhere() {
// 更新的字段值数据
// map推荐
values := map[string]any{
"subject": "Where Update Row",
"likes": 1001,
}
// 执行带有条件的更新
result := DB.Model(&Content{}).
// 全局更新
Where("1=1").
Updates(values)
if result.Error != nil {
log.Fatalln(result.Error)
}
// 获取更新结果,更新的记录数量(受影响的记录数)
// 指的是修改的记录数,而不是满足条件的记录数
log.Println("updated rows num: ", result.RowsAffected)
}
func UpdateExpr() {
// 更新的字段值数据
// map推荐
values := map[string]any{
"subject": "Where Update Row",
// 值为表达式计算的结果时使用Expr类型
"likes": gorm.Expr("likes + ?", 10),
//"likes": "likes + 10",
// Incorrect integer value: 'likes + 10' for column 'likes' at row 1
}
// 执行带有条件的更新
result := DB.Model(&Content{}).
Where("likes > ?", 100).
Updates(values)
// [17.011ms] [rows:51] UPDATE `msb_content` SET `likes`=likes + 10,`subject`='Where Update Row',`updated_at`='2023-04-21 17:28:45.498' WHERE likes > 100 AND `msb_content`.`deleted_at` IS NULL
if result.Error != nil {
log.Fatalln(result.Error)
}
// 获取更新结果,更新的记录数量(受影响的记录数)
// 指的是修改的记录数,而不是满足条件的记录数
log.Println("updated rows num: ", result.RowsAffected)
}

@ -0,0 +1,19 @@
package gormExample
import "testing"
func TestUpdatePK(t *testing.T) {
UpdatePK()
}
func TestUpdateWhere(t *testing.T) {
UpdateWhere()
}
func TestUpdateNoWhere(t *testing.T) {
UpdateNoWhere()
}
func TestUpdateExpr(t *testing.T) {
UpdateExpr()
}
Loading…
Cancel
Save