gorm 基本使用 2

数据库连接时的一些配置

gorm 连接数据库时,可以配置一些参数,如下:

 

go

复制代码

var dsn = "root:123456@tcp(go-uccs-1:3306)/zero_study?charset=utf8mb4&parseTime=True&loc=Local&timeout=10s" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ SkipDefaultTransaction: true, // 跳过默认事务 NamingStrategy: schema.NamingStrategy{ TablePrefix: "f_", // 表名前缀 SingularTable: true, // 表名单数 NoLowerCase: true, // 表名不转小写 }, })

log 配置

gorm 默认只打印错误和慢 SQL,默认是不展示 log,配置 log 有三种方式

全局配置

 

go

复制代码

var log = logger.Default.LogMode(logger.Info) db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ Logger: log, })

局部配置

 

go

复制代码

db = db.Session(&gorm.Session{ Logger: log, })

db 对象配置

 

go

复制代码

db.Debug().AutoMigrate(&Student{})

gorm json tag

  • type: 定义字段类型
  • size: 定义字段大小
  • column: 自定义列名
  • primaryKey: 将列定义为主键
  • autoIncrement: 将列定义为自增
  • foreignKey: 定义外键关联
  • unique: 将列定义为唯一键
  • default: 定义列的默认值
  • not null: 定义列为非空
  • comment: 定义列的注释
  • embedded: 嵌入结构体
  • embeddedPrefix: 嵌入结构体的前缀
  • many2many: 定义多对多关系
  • joinForeignKey: 外键关联,修改主键名
  • joinReferences: 外键关联,修改引用名

Create

指针不传值,默认是 null,其他类型,不传值,默认是零值

 

go

复制代码

db.Create(&Student{Name: "zero", Age: 18})

对应的 sql 语句

 

sql

复制代码

INSERT INTO `student` (`name`,`age`) VALUES ('uccs',123)

批量

 

go

复制代码

students := []Student{{Name: "zero", Age: 18}, {Name: "uccs", Age: 183}} DB.Create(&students)

对应的 sql 语句

 

sql

复制代码

INSERT INTO `student` (`name`,`age`) VALUES ('zero',18),('uccs',183)

Take

查询数据库中第一条数据

 

go

复制代码

student := Student{} DB.Take(&student)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student` LIMIT 1

第二个参数

Take 第二个参数是主键查询

 

go

复制代码

DB.Debug().Take(&student, 2)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student` WHERE `student`.`id` = '2' LIMIT 1

Find

查询所有数据,如果结构体不是 slice 类型,会获取第一条数据,如果是 slice 类型,会获取所有数据

 

go

复制代码

student := Student{} DB.Find(&student) // 获取第一条数据 students := []Student{} DB.Find(&students) // 获取所有数据

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student`

Update 和 Updates

 

go

复制代码

student := []Student{} DB.Take(&student, 1).Update("name", "uccs") // 更新一条记录的一个属性 DB.Debug().Take(&student, 1).Updates(&Student{Name: "astak", Age: 16}) // 更新一条记录的多个属性

对应的 sql 语句

 

sql

复制代码

UPDATE `student` SET `name`='uccs' WHERE `student`.`id` = 1 AND `id` = 1 LIMIT 1

Delete

 

go

复制代码

student := Student{} DB.Debug().Delete(&student, 1)

对应的 sql 语句

 

sql

复制代码

DELETE FROM `student` WHERE `student`.`id` = 1

Where

 

go

复制代码

student := &Student{} DB.Debug().Where("name = ?", "zero").Find(&student) // 等同于 DB.Debug().Find(&student, "name=?", "uccs")

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student` WHERE name = 'zero'

Select

Select 选择需要查询的字段

 

go

复制代码

student := &Student{} DB.Debug().Select("name").Find(&student)

对应的 sql 语句

 

sql

复制代码

SELECT `name` FROM `student`

Scan

Scan 是根据 json tag 来选择字段

 

go

复制代码

s := []struct { Name string `gorm:"column:name"` }{} student := &Student{} DB.Debug().Model(student).Select("name").Scan(&s)

对应的 sql 语句

 

sql

复制代码

SELECT `name` FROM `student`

Order

 

go

复制代码

student := &[]Student{}

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student` ORDER BY age desc

Limit 和 Offset

 

go

复制代码

student := &[]Student{} DB.Debug().Limit(2).Offset(2).Find(student)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student` LIMIT 2 OFFSET 2

Distinct

 

go

复制代码

ageList := []int{} DB.Debug().Model(&Student{}).Select("age").Distinct("age").Scan(&ageList) // 效果是一样的 DB.Debug().Model(student).Select("distinct age").Scan(&ageList)

对应的 sql 语句

 

sql

复制代码

SELECT DISTINCT `age` FROM `student`

Group

 

go

复制代码

g := []struct { Count int Name string }{} DB.Debug().Model(&Student{}).Select("count(name) as count, name").Group("name").Scan(&g)

对应的 sql 语句

 

sql

复制代码

SELECT count(name) as count, name FROM `student` GROUP BY `name`

 

go

复制代码

g := []struct { Count int Name string NameList string }{} DB.Debug().Model(&Student{}).Select("group_concat(name) as name_list, count(name) as count, name").Group("name").Scan(&g)

对应的 sql 语句

 

sql

复制代码

SELECT group_concat(name) as name_list, count(name) as count, name FROM `student` GROUP BY `name`

Raw

Raw 执行原生 sql

 

go

复制代码

s := []struct { Id int Name string Age int }{} DB.Raw("SELECT * FROM student WHERE id = ?", 6).Scan(&s)

Scopes

 

go

复制代码

s := []Student{} DB.Debug().Model(&Student{}).Scopes(GreaterThan).Find(&s)

子查询

 

go

复制代码

s := []Student{} DB.Debug().Model(&Student{}).Where("age > (?)", DB.Model(&Student{}).Select("avg(age) as age")).Find(&s)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student` WHERE age > (SELECT avg(age) as age FROM `student`)

具名参数

 

go

复制代码

DB.Raw("SELECT * FROM student_table WHERE id = @id", sql.Named("id", 6)).Scan(&s) DB.Raw("SELECT * FROM student_table WHERE id = @id", map[string]any{"id": 6}).Scan(&s)

一对多

Class.Id 和 Student.ClassId 是外键关联,他们的 json tag 必须一致

外键关联:表名 + Id

 

go

复制代码

type Class struct { Id int `gorm:"primaryKey;autoIncrement;"` Name string Students []Student } type Student struct { Id int `gorm:"primaryKey;autoIncrement"` Name string Age int ClassId int Class Class } db.AutoMigrate(&Student{}, &Class{})

重写外键关联

两边都要加上 foreignKey:ClassId1 的 json tag

 

go

复制代码

type Class struct { Id int `gorm:"primaryKey;autoIncrement;"` Name string Students []Student } type Student struct { Id int `gorm:"primaryKey;autoIncrement"` Name string Age int ClassId int Class Class } db.AutoMigrate(&Student{}, &Class{})

创建 class 带上 student

 

go

复制代码

DB.Debug().Create(&Class{ Name: "一年级1班", Students: []Student{ {Name: "uccs", Age: 8}, {Name: "astak", Age: 7}, }, })

对应的 sql 语句

 

sql

复制代码

INSERT INTO `student` (`name`,`age`,`class_id`) VALUES ('uccs',8,1),('astak',7,1) ON DUPLICATE KEY UPDATE `class_id`=VALUES(`class_id`) INSERT INTO `class` (`name`) VALUES ('一年级1班')

创建 student 关联 class

  • classId 必须存在
     

    go

    复制代码

    DB.Debug().Create(&Student{ Name: "李四", Age: 10, ClassId: 1, // 如果 classId 不存在会报错 }) 对应的 sql 语句
     

    sql

    复制代码

    INSERT INTO `student` (`name`,`age`,`class_id`) VALUES ('李四',10,1)
  • 创建 student 时同时创建 class
     

    go

    复制代码

    DB.Debug().Create(&Student{ Name: "李四", Age: 10, Class: Class{ Name: "一年级2班", }, }) 对应的 sql 语句
     

    sql

    复制代码

    INSERT INTO `class` (`name`) VALUES ('一年级2班') ON DUPLICATE KEY UPDATE `id`=`id` INSERT INTO `student` (`name`,`age`,`class_id`) VALUES ('李四',10,2)
  • 先查询已存在的数据
     

    go

    复制代码

    c := Class{} DB.Debug().Take(&c, 1) DB.Debug().Create(&Student{ Name: "小红", Age: 10, Class: c, }) 对应的 sql 语句
     

    sql

    复制代码

    SELECT * FROM `class` WHERE `class`.`id` = 1 LIMIT 1 INSERT INTO `class` (`name`,`id`) VALUES ('一年级1班',1) ON DUPLICATE KEY UPDATE `id`=`id` INSERT INTO `student` (`name`,`age`,`class_id`) VALUES ('小红',10,1)

给 class 添加 student

 

go

复制代码

c := Class{} DB.Debug().Take(&c, 1) // 查询 Class s := Student{} DB.Debug().Take(&s, 8) // 查询 Student // 给 class 的 Students 添加 student DB.Debug().Model(&c).Association("Students").Append(&s)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `class` WHERE `class`.`id` = 1 LIMIT 1 SELECT * FROM `student` WHERE `student`.`id` = 8 LIMIT 1 INSERT INTO `student` (`name`,`age`,`class_id`,`id`) VALUES ('王五',3,1,8) ON DUPLICATE KEY UPDATE `class_id`=VALUES(`class_id`)

给 student 添加 class

 

go

复制代码

c := Class{} DB.Debug().Take(&c, 1) s := Student{} DB.Debug().Take(&s, 8) DB.Debug().Model(&s).Association("Class").Append(&c)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `class` WHERE `class`.`id` = 1 LIMIT 1 SELECT * FROM `student` WHERE `student`.`id` = 8 LIMIT 1 INSERT INTO `class` (`name`,`id`) VALUES ('一年级1班',1) ON DUPLICATE KEY UPDATE `id`=`id` UPDATE `student` SET `class_id`=1 WHERE `id` = 8

预加载

 

go

复制代码

s := Student{} DB.Debug().Preload("Class").Take(&s)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `class` WHERE `class`.`id` = 1 SELECT * FROM `student` LIMIT 1

带条件的预加载
 

go

复制代码

s := Student{} DB.Debug().Preload("Class", "id = ?", 2).Take(&s)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `class` WHERE `class`.`id` = 1 AND id = 2 SELECT * FROM `student` LIMIT 1

自定义预加载
 

go

复制代码

s := Student{} DB.Debug().Preload("Class", func(db *gorm.DB) *gorm.DB { return db.Where("id = ?", 2) }).Take(&s)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `class` WHERE `class`.`id` = 1 AND id = 2 SELECT * FROM `student` LIMIT 1

删除

 

go

复制代码

c := Class{} DB.Debug().Preload("Students").Take(&c, 1) DB.Debug().Model(&c).Association("Students").Delete(&c.Students)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `student` WHERE `student`.`class_id` = 1 SELECT * FROM `class` WHERE `class`.`id` = 1 LIMIT 1 UPDATE `student` SET `class_id`=NULL WHERE `student`.`class_id` = 1 AND `student`.`id` IN (1,2,3,4,7,8)

一对一

 

go

复制代码

type User struct { ID uint Name string Age int Gender bool UserInfo UserInfo } type UserInfo struct { UserID uint User *User ID uint Addr string Like string } db.AutoMigrate(&UserInfo{}, &User{})

多对多

 

go

复制代码

type Tag struct { ID uint Name string Articles []Article `gorm:"many2many:article_tags"` } type Article struct { ID uint Title string Tags []Tag `gorm:"many2many:article_tags"` } db.AutoMigrate(&Article{}, &Tag{})

更新(先删除再添加)

 

go

复制代码

// 先删除 a := Article{} DB.Debug().Preload("Tags").Take(&a, 2) DB.Model(&a).Association("Tags").Delete(a.Tags) // 再更新 t := Tag{} DB.Debug().Take(&t, 1) DB.Debug().Model(&a).Association("Tags").Append(&t)

对应的 sql 语句

 

sql

复制代码

-- 先删除 SELECT * FROM `article_tags` WHERE `article_tags`.`article_id` = 2 SELECT * FROM `tag` WHERE `tag`.`id` IN (3,4) SELECT * FROM `article` WHERE `article`.`id` = 2 LIMIT 1 DELETE FROM `article_tags` WHERE `article_tags`.`article_id` = 2 AND `article_tags`.`tag_id` = 1 -- 再更新 SELECT * FROM `tag` WHERE `tag`.`id` = 1 LIMIT 1 INSERT INTO `tag` (`name`,`id`) VALUES ('python',1) ON DUPLICATE KEY UPDATE `id`=`id` INSERT INTO `article_tags` (`article_id`,`tag_id`) VALUES (2,1) ON DUPLICATE KEY UPDATE `article_id`=`article_id`

更新(替换)

 

go

复制代码

a := Article{} DB.Debug().Preload("Tags").Take(&a, 2) t := Tag{} DB.Debug().Take(&t, 6) DB.Debug().Model(&a).Association("Tags").Replace(&t)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `article_tags` WHERE `article_tags`.`article_id` = 2 SELECT * FROM `tag` WHERE `tag`.`id` = 1 SELECT * FROM `article` WHERE `article`.`id` = 2 LIMIT 1 SELECT * FROM `tag` WHERE `tag`.`id` = 6 LIMIT 1 INSERT INTO `tag` (`name`,`id`) VALUES ('后端',6) ON DUPLICATE KEY UPDATE `id`=`id` INSERT INTO `article_tags` (`article_id`,`tag_id`) VALUES (2,6) ON DUPLICATE KEY UPDATE `article_id`=`article_id` DELETE FROM `article_tags` WHERE `article_tags`.`article_id` = 2 AND `article_tags`.`tag_id` <> 6

自定义连接表

 

go

复制代码

type Tag struct { ID uint Name string Articles []Article `gorm:"many2many:article_tags"` // 反向引用 } type Article struct { ID uint Title string Tags []Tag `gorm:"many2many:article_tags"` } type ArticleTag struct { ArticleID uint `gorm:"primaryKey"` TagID uint `gorm:"primaryKey"` CreatedAt time.Time `json:"created_at"` }

这里存在反向引用,所以第三张表中 create_at 没法创建

 

go

复制代码

DB.Debug().SetupJoinTable(&Article{}, "Tags", &ArticleTag{}) DB.AutoMigrate(&Article{}, &Tag{}, &ArticleTag{})

所以有两种方法:

  1. 删除反向引用
     

    go

    复制代码

    type Tag struct { ID uint Name string // Articles []Article `gorm:"many2many:article_tags"` // 反向引用 }
  2. Tag 表也进行自定义连接
     

    go

    复制代码

    DB.Debug().SetupJoinTable(&Tag{}, "Articles", &ArticleTags{})
添加文章并添加标签,自动关联

ArticleTag 表中 CreatedAt 字段在数据创建时,会自动填充上时间,如果是其他字段,需要用 hook 函数 BeforeCreate 来填充

 

go

复制代码

DB.Debug().Create(&Article{ Title: "flask基础", Tags: []Tag{{Name: "python"}, {Name: "flask"}}, })

对应的 sql 语句

 

sql

复制代码

INSERT INTO `tag` (`name`) VALUES ('python'),('flask') ON DUPLICATE KEY UPDATE `id`=`id` INSERT INTO `article_tag` (`article_id`,`tag_id`,`created_at`) VALUES (1,1,'2024-05-29 20:11:20.973'),(1,2,'2024-05-29 20:11:20.973') ON DUPLICATE KEY UPDATE `article_id`=`article_id` INSERT INTO `article` (`title`) VALUES ('flask基础')

添加文章,关联已有标签
 

go

复制代码

t := []Tag{} DB.Debug().Find(&t, "name in ?", []string{"python"}) DB.Debug().Create(&Article{ Title: "Diango基础", Tags: t, })

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `tag` WHERE name in ('python') INSERT INTO `tag` (`name`,`id`) VALUES ('python',1) ON DUPLICATE KEY UPDATE `id`=`id` INSERT INTO `article_tag` (`article_id`,`tag_id`,`created_at`) VALUES (2,1,'2024-05-29 20:19:29.048') ON DUPLICATE KEY UPDATE `article_id`=`article_id` INSERT INTO `article` (`title`) VALUES ('Diango基础')

给已有的文章关联标签
 

go

复制代码

t := []Tag{} DB.Debug().Find(&t, "name in ?", []string{"golang"}) a := Article{} DB.Debug().Take(&a, "title = ?", "golang基础") DB.Debug().Model(&a).Association("Tags").Append(t)

对应的 sql 语句

 

sql

复制代码

SELECT * FROM `tag` WHERE name in ('golang') SELECT * FROM `article` WHERE title = 'golang基础' LIMIT 1 INSERT INTO `tag` (`name`,`id`) VALUES ('golang',3) ON DUPLICATE KEY UPDATE `id`=`id` INSERT INTO `article_tag` (`article_id`,`tag_id`,`created_at`) VALUES (3,3,'2024-05-29 20:24:25.459') ON DUPLICATE KEY UPDATE `article_id`=`article_id`

存储 json 数据

 

go

复制代码

type Auth struct { ID uint Info Info `gorm:"type:string"` // 不指定 type 默认是 blob } type Info struct { Status string `json:"status"` Addr string `json:"addr"` Age uint `json:"age"` } func (i *Info) Scan(value interface{}) error { bytes, ok := value.([]byte) if !ok { return errors.New(fmt.Sprintf("failed to unmarshal json value: ", value)) } return json.Unmarshal(bytes, i) } func (i Info) Value() (driver.Value, error) { return json.Marshal(i) } DB.Debug().Create(&Auth{ Info: Info{ Status: "success", Addr: "上海", Age: 18, }, }) auth := Auth{} DB.Take(&auth, 1)

对应的 sql 语句

 

sql

复制代码

INSERT INTO `auth` (`info`) VALUES ('{"status":"success","addr":"上海","age":18}') SELECT * FROM `auth` WHERE `auth`.`id` = 1 LIMIT 1

枚举

 

go

复制代码

func (s Status) MarshalJSON() ([]byte, error) { return json.Marshal(string(s)) } func (s Status) String() string { var str string switch s { case Running: str = "Running" case Offline: str = "Offline" case Except: str = "Except" } return str } type Host struct { ID uint IP string Status Status `gorm:"size:8"` } DB.Debug().Create(&Host{ IP: "192.168.1.1", Status: Running, }) h := Host{} DB.Take(&h) d, _ := json.Marshal(&h) fmt.Println(string(d))

hook

CreateCreateInBatches,Save 是会运行

 

go

复制代码

func (u *Student) BeforeCreate(tx *gorm.DB) error { u.Age = 18 return nil }

错误处理

 

go

复制代码

err := DB.Task(&Student{}).Error // 错误类型判断 err == Gorm.ErrRecordNotFound

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值