Java白深

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
统计
 

 Day2:GORM入门

1.环境的安装

在项目文件的terminal中输入下面两条命令进行gorm安装

1
2
3
go get gorm.io/driver/mysql
 
go get gorm.io/gorm

2.安装好之后使用以下代码进行检测,其中的地址拼接是重点

1
"%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, Dbname, timeout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func init() {
    username := "root"   //账号
    password := "147258" //密码
    host := "127.0.0.1"  //数据库地址,可以是Ip或者域名
    port := 3306         //数据库端口
    Dbname := "gorm"     //数据库名
    timeout := "10s"     //连接超时,10秒
 
    // root:root@tcp(127.0.0.1:3306)/gorm?
    dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, Dbname, timeout)
    //连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
        NamingStrategy: schema.NamingStrategy{
            TablePrefix: "f_"// 表名前缀
            NoLowerCase: false, // 关闭小写转换
        },
    })
    if err != nil {
        panic("连接数据库失败, error=" + err.Error())
    }
    // 连接成功
    fmt.Println(db)
    DB = db
}

3.连接数据库的重点语句是gorm.open(数据库类型.open(数据库拼接地址)),在Open中添加&gorm.config(根据需求添加相关配置)

例如数据表命名的策略如下所示

1
2
3
4
5
6
7
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  NamingStrategy: schema.NamingStrategy{
    TablePrefix:   "f_"// 表名前缀
    SingularTable: false, // 单数表名
    NoLowerCase:   false, // 关闭小写转换
  },
})

 

4.打印日志的三种方式

1 1.DB.Debug().AutoMigrate(&Student{})
2 2.展示部分日志:var model Student session := DB.Session(&gorm.Session{Logger: newLogger}) 
3         session.First(&model)
4 3.var mysqlLogger logger.Interface 
5 // 要显示的日志等级 mysqlLogger = logger.Default.LogMode(logger.Info) 
6   db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ Logger: mysqlLogger, })

 

 Day2:GORM模型定义、单表操作

一、模型定义

1.当自动创建表的结构太大时,可以使用gorm:size:大小,进行操作,如下图所示

 操作方式,实现结果如下:

 

 

字段标签,将gorm后面的size替换下面指令就行

type 定义字段类型

size 定义字段大小

column 自定义列名

primaryKey 将列定义为主键

unique 将列定义为唯一键

default 定义列的默认值

not null 不可为空

embedded 嵌套字段

embeddedPrefix 嵌套字段前缀

comment 注释

多个标签之前用 ; 连接

 二、单表操作

1.使用DB.create(interface{})进行插入数据

1
2
3
4
5
6
7
8
9
DB.AutoMigrate(&students{})
    email := "123456@qq.com"
    s := students{
        Name:   "xx",
        Age:    22,
        Gender: false,
        Email:  &email,
    }
    DB.Create(&s)

 2.批量插入

1
2
3
4
5
6
7
8
9
for i := 0; i < 10; i++ {
        studentsList = append(studentsList, students{
            Name:   fmt.Sprintf("Robot%d号", i+1), //使用Sprintf可以拼接字符串
            Age:    22,
            Gender: true,
            Email:  nil,
        })
    }
    DB.Create(&studentsList)

 3.单表查询

1
2
3
4
5
6
7
8
9
10
11
var student students
    DB.Take(&student)   //查询一个student数据
    fmt.Println(student)
    DB = DB.Session(&gorm.Session{Logger: mysqlLogger}) //打印操作日志
    var studentList []students  //查询所有students的数据
    DB.Take(&studentList)
    fmt.Println(studentList)
    DB.First(&studentList)
    fmt.Println(studentList)
    DB.Last(&studentList)
    fmt.Println(studentList)

4.根据主键查询

1
2
3
//根据主键查询,查询主键为3的数据 
    DB.Take(&studentList, 3)    //第二个参数是主键位置
    fmt.Println(studentList)

5.根据其他条件查询

1
2
3
4
5
6
7
8
9
//根据其他条件查询,查询名字为Robot5号的信息
    err := DB.Take(&studentList, "name=?", "Robot5号").Error
    switch err {
    case gorm.ErrRecordNotFound:
        fmt.Println("没有找到")
    default:
        fmt.Println("sql错误")
    }
    fmt.Println(studentList)

6.根据结构体查询

1
2
3
4
var student students
    student.ID = 3
    DB.Take(&student)
    fmt.Println(student)

7.查询多条记录

1
2
3
4
5
6
count := DB.Find(&studentList).RowsAffected //获取查询的记录数
    fmt.Println(count)
    for _, student := range studentList {
        data, _ := json.Marshal(student)
        fmt.Println(string(data))
    }

8.根据主键查询多条记录

1
2
3
//DB.Find(&studentList, []int{1, 3, 5, 7})
    //DB.Find(&studentList, 1, 3, 5, 7) // 一样的
    //fmt.Println(studentList)

9.根据其它条件查询多条记录

1
2
DB.Find(&studentList, "name in ?", []string{"Robot3号", "xx"})
    fmt.Println(studentList)

 三、更新表操作

1.更新所有字段,指定字段

1
2
3
4
5
6
7
//更新所有字段
    var student students
    email := "123456789@qq.com"
    DB.Take(&student) //获取第一个数据
    student.Age = 18  //更改第一个数据的年龄
    student.Email = &email
    student.XXX=xxx//使用select更新指定字段<br>DB.Select("age").Save(&student) //重新提交数据库DB.Save(&student) //重新提交数据库

2.批量更新

1
2
3
//批量更新
    var studentList []students
    DB.Find(&studentList, "age=?", 22).Update("email", "is22@qq.com")

3.更新多列

1
2
3
4
5
var studentList []students
    DB.Model(&studentList).Where("age=?", 22).Updates(map[string]any{
        "name":   "坨哥",
        "gender": false,
    })

4.根据ID删除

1
2
3
//根据ID删除行数据
    var student students
    DB.Delete(&student, 4)

 

 四、在重新创建新的go文件时遇到undefined DB 问题解决方案

 

问题原因:在一个go文件中创建DB连接数据库后,其它的go文件无法直接调用。

解决方案:因为所有的go文件都创建在一个目录中,导致出现以上问题。因此,将连接文件单独放在一个目录中,在其它文件中去调用连接数据的文件

方法如下:

 

 此时,在其它文件中调用DB就是已经连接好的DB状态了,调用形式如下

 

 Day3:GORM之高级查询

一.Where语句的使用

1
2
3
//查询用户名是xx的指令
    DB.Where("name=?", "李元芳").Find(&student)
    fmt.Println(student)//查询用户名不是XX的指令<br>DB.Where("name<>?", "李元芳").Find(&student)<br>for _, s := range student {<br>    fmt.Println(s)<br>}// 查询用户名包含 如燕,李元芳的<br>DB.Where("name in ?", []string{"李元芳", "枫枫"}).Find(&student)<br>fmt.Println(student)//模糊查询<br>DB.Where("name like ?", "李%").Find(&student)<br>fmt.Println(student)//根据多个条件查询<br>DB.Where("name like ? and email like ?", "李%", "%@lly.cn").Find(&student)<br>fmt.Println(student)//根据判断条件查询<br>DB.Where("age > ? and gender = ?", "20", "1").Find(&student)<br>fmt.Println(student)<br><br>//select 选择字段,没有选择的字段打印时都会赋零值,但是不改变表的实际内容<br>DB.Select("name", "age").Find(&student)<br>fmt.Println(student)<br><br>//使用scan,将select选择的字段存入另一个结构体中<br>var list []students<br>DB.Select("name", "age").Find(&student).Scan(&list)<br>fmt.Println(list)

二.排序

排序分为升序和降序

1
2
3
4
5
6
//降序排序
    DB.Order("age desc").Find(&student)
    fmt.Println(student)
    //升序排序
    DB.Order("age asc").Find(&student)
    fmt.Println(student)

三.分页查询

1
2
3
4
5
6
7
8
//分页查询
    // 一页多少条数据
    limit := 2
    // 第几页
    page := 1
    offset := (page - 1) * limit
    DB.Limit(limit).Offset(offset).Find(&student)
    fmt.Println(student)

四.去重

1
2
3
4
//去重.DB.table("数据表名称")
    var ageList []int
    DB.Table("f_students").Select("distinct age").Find(&ageList)
    fmt.Println(ageList)

五、分组查询

1
2
3
4
5
6
7
8
9
//以gender分类统计每类的总数,并且使用group_concat(name),将name也同时分类
    type AggeGroup struct {
        Gender int
        Count  int
        Name   string
    }
    var agg []AggeGroup
    DB.Table("f_students").Select("count(id) as count", "gender", "group_concat(name) as name").Group("gender").Scan(&agg)
    fmt.Println(agg

六、子查询

1
2
3
4
5
//子查询,嵌套查询
    var student []students
    //(?)  由括号包裹的问号表示函数
    DB.Table("f_students").Where("age>(?)", DB.Table("f_students").Select("avg(age)")).Find(&student)
    fmt.Println(student)//命名参数<br>DB.Where("name=@name and age = @age",<br>    map[string]any{<br>       "name": "枫枫",<br>       "age":  23,<br>    }).Find(&student)<br>fmt.Println(student)<br><br>//使用函数进行查询<br>var student []students<br>DB.Scopes(LikeLi).Find(&student)<br>fmt.Println(student)//创建查询函数,方便调用<br>func LikeLi(DB *gorm.DB) *gorm.DB {<br>    return DB.Where("name like ?", "李%")<br>}

Day4:GORM之一对多关系

 一、一对多关系创建

复制代码
package main

import "GROM_study/conjunction"

var DB = conjunction.DB

type User struct {
    ID       uint
    Name     string    `gorm:"size:8"`
    Articles []Article // 用户拥有的文章列表
}

type Article struct {
    ID     uint
    Title  string `gorm:"size:16"`
    UserID uint   // 属于   这里的类型要和引用的外键类型一致,包括大小
    User   User   // 属于
}

func main() {
    DB.AutoMigrate(&User{}, &Article{})
}
复制代码

二、一对多的添加

复制代码
 1 //DB.AutoMigrate(&User{}, &Article{})
 2     a1 := Article{Title: "python"}
 3     a2 := Article{Title: "golang"}
 4     user := User{Name: "枫枫", Articles: []Article{a1, a2}}
 5     DB.Create(&user)
 6 
 7     //创建文章关联用户
 8     a1 := Article{Title: "golang零基础入门", UserID: 1}
 9     DB.Create(&a1)
10     //给现有用户绑定文章
11     var user User
12     DB.Take(&user, 2) //取出第二个用户
13     var article Article
14     DB.Take(&article, 5)               //取出第五篇文章
15     user.Articles = []Article{article} //将第五篇文章关联到第二个用户
16     DB.Save(&user)
17 
18     //更改现有关联
19     var article Article
20     DB.Take(&article, 5)
21     article.UserID = 1
22     DB.Save(&article)
复制代码

三、一对多关系的查询和删除

1.查询

复制代码
//查询
    var user User
    DB.Take(&user, 1)
    fmt.Println(user)

    //上述查询并不能直接查询到另一个表的信息
    //因此我们需要使用预加载
    var user User
    //预加载方法中的字段,就是外键关联的属性名
    DB.Preload("Articles").Take(&user, 1)
    fmt.Println(user)

    //查询与一号书关联的用户有那些
    var article Article
    DB.Preload("User").Take(&article, 1)
    fmt.Println(article)

    //带条件的预加载
    var user User
    DB.Preload("Articles", "id = ?", 1).Take(&user, 1)
    fmt.Println(user)

    //自定义的预加载
    var user User
    DB.Preload("Articles", func(db *gorm.DB) *gorm.DB {
        return db.Where("id in ?", []int{1, 2})
    }).Take(&user, 1)
    fmt.Println(user)
复制代码

2.删除

复制代码
 1 //删除
 2     //级联删除,删除用户,与用户关联的文章也会删除
 3     var user User
 4     DB.Take(&user, 1)
 5     DB.Select("Articles").Delete(&user)
 6 
 7     //删除用户与文章之间的关联关系
 8     var user User
 9     DB.Preload("Articles").Take(&user, 2)
10     DB.Model(&user).Association("Articles").Delete(&user.Articles)
复制代码

Day5:GORM之多对多关系

 1.创建多对多关系表

复制代码
 1 package main
 2 
 3 import (
 4     "GROM_study/conjunction"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 var DB = conjunction.DB
10 
11 /**
12 文章有ID,名称title和标签tags,因为一个文章可能含有多个标签
13 同时一个标签可能属于多个文章
14 因此文章和标签之间存在多对多的关系
15 */
16 type Article struct {
17     ID    uint
18     Title string
19     Tags  []Tag `gorm:"many2many:article_tags"`
20 }
21 
22 /**
23 标签有ID和名称
24 */
25 type Tag struct {
26     ID   uint
27     Name string
28 }
29 
30 /**
31 建立文章标签关系表,分别将这两个表的ID作为主键
32 且参数名称是文章和标签表的名称拼接上ID
33 最后设置一个创建时间
34 */
35 type ArticleTag struct {
36     ArticleID uint `gorm:"primaryKey"`
37     TagID     uint `gorm:"primaryKey"`
38     CreatedAt time.Time
39 }
40 
41 func main() {
42     // 设置Article表与Tag表的联系为ArticleTag
43     DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
44     // 如果tag要反向应用Article,那么也得加上
45     // DB.SetupJoinTable(&Tag{}, "Articles", &ArticleTag{})
46     err := DB.AutoMigrate(&Article{}, &Tag{}, &ArticleTag{})
47     fmt.Println(err)
48 }
复制代码

2.对多对多关系的表进行相关操作

复制代码
//给文章添加标签
    DB.Create(&Article{
        Title: "语文",
        Tags: []Tag{
            {Name: "文科"},
            {Name: "难学"},
            {Name: "不易考高分"},
        }})

    //添加文章,关联已有标签
    var tags []Tag
    DB.Find(&tags, "name in ?", []string{"文科", "不易考高分"})
    DB.Create(&Article{
        Title: "政治",
        Tags:  tags,
    })

    //给文章打上标签
    article := Article{Title: "Python"}
    DB.Create(&article)

    var tags []Tag
    var ac Article
    DB.Find(&ac, "title = ?", "Golang")
    DB.Find(&tags, "name in ?", []string{"后端开发", "编程", "工科"})
    DB.Model(&ac).Association("Tags").Append(tags)

    //删除文章的标签,只保留后端开发这个标签
    var article Article
    var tags []Tag
    DB.Find(&tags, "name in ?", []string{"后端开发"})
    DB.Find(&article, "title = ?", "Golang")
    DB.Model(&article).Association("Tags").Replace(&tags)

    //查询文章列表,并显示标签
    var articles []Article
    DB.Preload("Tags").Find(&articles)
    fmt.Println(articles)
复制代码

 Day6.续GORM之多对多关系,自定义连接表主键

复制代码
 1 type UserModel struct {
 2   ID       uint
 3   Name     string
 4   Collects []ArticleModel `gorm:"many2many:user_collect_models;joinForeignKey:UserID;JoinReferences:ArticleID"`
 5 }
 6 
 7 type ArticleModel struct {
 8   ID    uint
 9   Title string
10 }
11 
12 // UserCollectModel 用户收藏文章表
13 type UserCollectModel struct {
14   UserID       uint         `gorm:"primaryKey"` // article_id
15   UserModel    UserModel    `gorm:"foreignKey:UserID"`
16   ArticleID    uint         `gorm:"primaryKey"` // tag_id
17   ArticleModel ArticleModel `gorm:"foreignKey:ArticleID"`
18   CreatedAt    time.Time
19 }
复制代码
复制代码
var collects []UserCollectModel

var user UserModel
DB.Take(&user, "name = ?", "枫枫")
// 这里用map的原因是如果没查到,那就会查0值,如果是struct,则会忽略零值,全部查询
DB.Debug().Preload("UserModel").Preload("ArticleModel").Where(map[string]any{"user_id": user.ID}).Find(&collects)

for _, collect := range collects {
  fmt.Println(collect)
}
复制代码
复制代码
type Status int
type Host struct {
    ID     uint   `json:"id"`
    IP     string `json:"ip"`
    Status Status `gorm:"size:8" json:"status"`
}

const (
    Running Status = 1
    Except  Status = 2
    OffLine Status = 3
)

//在枚举中都要实现这个方法
func (s Status) MarshalJSON() ([]byte, error) {
    return json.Marshal(s.String())
}

func (s Status) String() string {
    var str string
    switch s {
    case Running:
        str = "Running"
    case Except:
        str = "Except"
    case OffLine:
        str = "Status"
    }
    return str
}

func main(){
DB.AutoMigrate(&Host{})
    //DB.Create(&Host{
    //    IP:     "192.168.200.12",
    //    Status: Running,
    //})
    var host Host
    DB.Take(&host)
    fmt.Println(host)
    fmt.Printf("%#v,%T\n", host.Status, host.Status)
    data, _ := json.Marshal(host)
    fmt.Println(string(data))
}
复制代码

 事务的提交

复制代码
package main

import (
    "GROM_study/conjunction"
    "fmt"
    "gorm.io/gorm"
)

var DB = conjunction.DB

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"姓名"`
    Money int    `json:"money"`
}

func main() {

    //DB.AutoMigrate(&User{})

    var p1, p2 User
    DB.Take(&p1, "name = ?", "张三")
    DB.Take(&p2, "name = ?", "李四")
    //开启事务
    DB.Transaction(func(tx *gorm.DB) error {
        //p1转账100给p2
        if p1.Money >= 100 {
            p1.Money -= 100
            err := tx.Model(&p1).Update("money", p1.Money).Error
            if err != nil {
                fmt.Println(err)
                return err
            }
            //转账成功再给p2加100
            p2.Money += 100
            err = tx.Model(&p2).Update("money", p2.Money).Error
            if err != nil {
                fmt.Println(err)
                return err
            }
        }

        return nil
    })
}
复制代码

手动提交

复制代码
// 开始事务
tx := db.Begin()

// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)

// ...

// 遇到错误时回滚事务
tx.Rollback()

// 否则,提交事务
tx.Commit()
复制代码

具体示例如下

复制代码
var zhangsan, lisi User
DB.Take(&zhangsan, "name = ?", "张三")
DB.Take(&lisi, "name = ?", "李四")

// 张三给李四转账100元
tx := DB.Begin()

// 先给张三-100
zhangsan.Money -= 100
err := tx.Model(&zhangsan).Update("money", zhangsan.Money).Error
if err != nil {
  tx.Rollback()
}

// 再给李四+100
lisi.Money += 100
err = tx.Model(&lisi).Update("money", lisi.Money).Error
if err != nil {
  tx.Rollback()
}
// 提交事务
tx.Commit()
复制代码

 

posted on   DengSr  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
 
点击右上角即可分享
微信分享提示