当前位置:   article > 正文

Go实战Gin+Vue+微服务打造秒杀商城第二课 gorm教程_go gim vue 微服务

go gim vue 微服务

gorm介绍

一、什么是orm

Object-Relationl Mapping,即对象关系映射,这里的Relationl指的是关系型数据库

它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。

二、gorm

1.Golang写的,GitHub上活跃度很高的orm库

2.特点:

  • 全功能ORM(几乎)
  • 关联(包含一个,包含多个,属于,多对多,多种包含)
  • Callbacks(创建/保存/更新/删除/查找之前/之后)
  • 预加载(急加载)
  • 事务
  • 复合主键
  • SQL Builder
  • 自动迁移
  • 日志
  • 可扩展,编写基于GORM回调的插件
  • 每个功能都有测试
  • 开发人员友好

3.安装

go get github.com/jinzhu/gorm
  • 1

4.官方文档:http://gorm.book.jasperxu.com/

DDL操作

对数据库,表,字段等的操作,这里指的DDl不包括数据库

一、数据库

  1. 连接数据库
// 引入gorm及驱动包
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"


db,db_err := gorm.Open("mysql","root:Qazwsx123@[tcp](localhost:3306)/test_gorm?charset=utf8&parseTime=True&loc=Local")

if err!= nil{
    panic(err)
}
defer db.Close() // 关闭连接


// loc=Local:表示根据本地时区走
// parseTime:处理time.Time
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

二、表

1.创建表

type User struct {
    Id int
    Name string
    Age int
}


// 创建表
db.Table("user").CreateTable(&User{})   // 指定表名

db.CreateTable(&User{})                 // 不指定表名,模型后面会加个s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2.删除表

db.DropTable(&User{})       // 使用模型名
db.DropTable("users")       // 直接使用表名

db.DropTableIfExists(&User{}) // 先判断是否存在再删除,可以接受多个参数,模型和字符串都可以
  • 1
  • 2
  • 3
  • 4

3.检查表是否存在

is_has := db.HasTable(&User{})   // 使用模型

is_has := db.HasTable("users")     // 使用表名
fmt.Println(is_has)
  • 1
  • 2
  • 3
  • 4

三、列(不建议进行操作,直接在模型上指定迁移即可)

1.修改列

// 修改模型`User`的description列的数据类型为`text`
db.Model(&User{}).ModifyColumn("description", "text")
  • 1
  • 2

2.删除列

// 删除模型`User`的description列
db.Model(&User{}).DropColumn("description")
  • 1
  • 2

3.添加外键

db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")

// 第一个参数: 外键字段
// 第二个参数 : 外键表(字段)
// 第三个参数 : ONDELETE
// 第四个参数 : ONUPDATE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4.索引

// 为`name`, `age`列添加索引`idx_user_name_age`
db.Model(&User{}).AddIndex("idx_user_name_age", "name", "age")

// 为多列添加唯一索引
db.Model(&User{}).AddUniqueIndex("idx_user_name_age", "name", "age")
  • 1
  • 2
  • 3
  • 4
  • 5

四、数据库迁移

1.自动迁移

自动迁移仅仅会创建表,添加缺少列和索引,并且不会改变现有列的类型或删除未使用的列以保护数据

db.AutoMigrate(&User{})

db.AutoMigrate(&User{}, &Product{}, &Order{})

// 创建表时添加表后缀
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

DML操作

是对数据的操作

一、增删改查

1.增

db.Create(&User{Id:1,Name:"hallen",Age:18})
  • 1

2.查

var user User
db.First(&user,1)  // 默认使用id字段
fmt.Println(user)
db.First(&user,"name=?","hallen")       // 查询指定字段
fmt.Println(user)
  • 1
  • 2
  • 3
  • 4
  • 5

3.改:先查再改

var user User
db.First(&user,1)  // 默认使用id字段

db.Model(&user).Update("age",20)        // 这里的Model是查询出来的结构体对象user,不是模型
  • 1
  • 2
  • 3
  • 4

4.删:先查再改

var user User
db.First(&user,1)  // 默认使用id字段

db.Delete(&user)
  • 1
  • 2
  • 3
  • 4

模型定义一

一、模型定义的作用

用作数据库数据转换和自动建表

二、模型名和表名的映射关系

  1. 规则
    • 第一个大写字母变为小写,
    • 遇到其他大写字母变为小写并且在前面加下划线,
    • 连着的几个大写字母,只有第一个遵循上面的两条规则,其他的大写字母转为小写,不加下划线,遇到小写,前面的第一个大写字母变小写并加下划线
    • 复数形式
  2. 举例
    • User --> users 首字母小写,复数
    • UserInfo --> user_infos
    • DBUserInfo --> db_user_infos
    • DBXXXXUserInfo --> dbxxxx_user_infos

三、在默认表名上加其他规则

// 在默认表名前加sys_前缀

gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
    return "sys_" + defaultTableName;
}


自定义表名:
func (模型) TableName() string{
    return "新的表名"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

四、结构体字段名和列名的对应规则

  1. 规则 * 列名是字段名的蛇形小写
  2. 举例
    • Name --> name
    • CreatedTime --> create_time
  3. 可以通过gorm标签指定列名,AnimalId int64 gorm:"column:beast_id"

五、gorm.Model

基本模型定义gorm.Model,包括字段ID,CreatedAt,UpdatedAt,DeletedAt

只需要在自己的模型中指定gorm.Model匿名字段,即可使用上面的四个字段

// 添加字段 `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`
type User struct {
    gorm.Model
    Name string
}
  • 1
  • 2
  • 3
  • 4
  • 5

ID:主键自增长

CreatedAt:用于存储记录的创建时间

UpdatedAt:用于存储记录的修改时间

DeletedAt:用于存储记录的删除时间

模型定义二

一、结构体标签gorm的使用

type UserInfo struct {
    Id int `gorm:"primary_key"`
    Name string `gorm:"index"`
    Age int 
}
  • 1
  • 2
  • 3
  • 4
  • 5

二、gorm标签属性值

  • -: 忽略,不映射这个字段 gorm:"-"
  • primary_key:主键 gorm:"primary_key"
  • AUTO_INCREMENT:自增 gorm:"AUTO_INCREMENT"
  • not null:不为空,默认为空 gorm:"not null"
  • index:索引, gorm:"index"
    • 创建索引并命名: gorm:"index:idx_name_code"
    • 优化查询,相当于图书的目录
  • unique_index:唯一索引 gorm:"unique_index"
  • unique:唯一 gorm:"unique"
  • column:指定列名 gorm:"column:user_name"
  • size:字符串长度,默认为255 gorm:"size:64"
  • type:设置sql类型 gorm:"type:varchar(100)" // 不推荐直接改类型
  • default default:'galeone' 默认值

多个属性值之间用分号分隔(英文的;):gorm:"size:64;not null"

模型定义三

一、一对一

1.属于

     // UserProfile属于User,外键是在UserProfile模型,外键字段为:UId


     type User struct {
        Id int
        Name string
        Age int
        Addr string

    }


    type UserProfile struct {
        Id int
        Pic string
        CPic string
        Phone string
        User User `gorm:"ForeignKey:UId;AssociationForeignKey:Id"`  // 关联关系
        //UserID int  // 默认关联字段为Id
        UId int // uid
    }

    注:

    // 外键默认使用UserID,如果不指定外键,则使用默认的外键字段,
    // 默认关联ID,通过AssociationForeignKey指定关联字段
  • 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

2.包含

     // UserProfile 包含一个 User, 外键在User模型,外键字段为:PId

    type User struct {
        Id int
        Name string
        Age int
        Addr string
        PId int

    }


    type UserProfile struct {
        Id int
        Pic string
        CPic string
        Phone string
        User User `gorm:"ForeignKey:PId;AssociationForeignKey:Id"`  // 关联关系

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

属于:关系和外键在同一方,有关系的那一方属于另外一个模型

包含:关系和外键不在同一方,有关系的那一方包含另外一个有外键的模型

二、一对多

    type User2 struct {
        Id int
        Name string
        Age int
        Addr string
        Articles []Article `gorm:"ForeignKey:UId;AssociationForeignKey:Id"`
    }

    type Article struct {
        Id int
        Title string
        Content string
        Desc string
        // 外键
        UId int
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

三、多对多

    type Article2 struct {
        AId int `gorm:"primary_key:true"`
        Title string
        Content string
        Desc string
        Tags []Tag `gorm:"many2many:Article2s2Tags"`  // ;ForeignKey:AId;AssociationForeignKey:TId

    }

    type Tag struct {
        TId int `gorm:"primary_key:true"`
        Name string
        Desc string
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

创建/更新时不会保存关联:gorm:"save_associations:false"

一对一操作

一、增加

    user_profile := relate_tables.UserProfile{
        Pic:"1.jpg",CPic:"2.jpg",Phone:"xxx",
        User:relate_tables.User{Name:"hallen",Age:18,Addr:"xxx"},
        }
    result := db.Create(&user_profile)



    默认是关联创建或更新的
    创建/更新时不会保存关联:`gorm:"save_associations:false"`
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

二、查询

1.第一种方式:Association

// 先查询出来,在根据Association属性值关联查询,Association的值为关联表的模型名称
var u_profile relate_tables.UserProfile
db.First(&u_profile,1)
fmt.Println(u_profile)
db.Model(&u_profile).Association("User").Find(&u_profile.User)
  • 1
  • 2
  • 3
  • 4
  • 5

2.第二种方式:Preload

var u_profile relate_tables.UserProfile
db.Debug().Preload("User").First(&u_profile,1)   // 关系名
fmt.Println(u_profile)
  • 1
  • 2
  • 3

3.第三种方式:Related

var user_profile3 relate_tables.UserProfile
db.First(&user_profile3,1)

var user relate_tables.User
db.Model(&user_profile3).Related(&user,"User")
  • 1
  • 2
  • 3
  • 4
  • 5

三、更新

// 先关联查询出来,再更新关联表中的字段
var u_profile1 relate_tables.UserProfile

db.Debug().Preload("User").First(&u_profile1,1)
fmt.Println(u_profile1)
db.Model(&u_profile1.User).Update("p_id",2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

四、删除

// 通过主表删除关联表中的
var u_profile2 relate_tables.UserProfile
db.Debug().Preload("User").First(&u_profile2,1)
db.Delete(&u_profile2.User)
  • 1
  • 2
  • 3
  • 4

一对多操作、

一、增加

user := relate_tables.User2{
        Name:"halle",
        Age:18,
        Addr:"xxx",
        Articles:[]relate_tables.Article{{
            Title:"标题测试",
            Content:"内容测试",
            Desc:"描述测试",
        },{
            Title:"标题测试2",
            Content:"内容测试2",
            Desc:"描述测试2",
        },
        },
    }

ret := db.Create(&user)

fmt.Println(ret.RowsAffected)
fmt.Println(ret.Error)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

二、查询

1.Preload

var user2 relate_tables.User2

db.Preload("Articles").Find(&user2,2)    // 关系名
fmt.Println(user2)
  • 1
  • 2
  • 3
  • 4

2.Association

var user2 relate_tables.User2

db.First(&user2,2)
db.Model(&user2).Association("Articles").Find(&user2.Articles)
fmt.Println(user2)
  • 1
  • 2
  • 3
  • 4
  • 5

3.Related

var user2 relate_tables.User2

db.First(&user2,1)

var articles []relate_table.Article

db.Model(&user2).Related(&articles, "Articles")     // 关系名称
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三、更新

// 先查询
var user2 relate_tables.User2

db.Preload("Articles").Find(&user2,2)    // 关系名

// 再更新,更新指定条件,不然会把所有满足条件的都更新

db.Model(&user2.Articles).Where("title=? and uid=?","标题测试2",2).Update("uid",3) // name和uid限制条件

// update只能更新一个字段,如果想同时更新多个字段,使用save,后面会讲
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四、删除

// 先查询
var user2 relate_tables.User2
db.Preload("Articles").Find(&user2,2)    // 关系名



// 再删除,删除要指定条件,不然会把所有满足条件的都删除
db.Delete(&user2.Articles,"title=? and uid=?","标题测试3",3)

// 或者使用where
db.Where("title=? and uid=?","标题测试3",3).Delete(&user2.Articles)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

多对多操作

一、增加

// 一篇文章有多个帖子
article := relate_tables.Article2{
        Title:"测试多对多标题1",
        Content:"测试多对多内容1",
        Desc:"测试多对多描述1",
        Tags:[]relate_tables.Tag{{
            Name:"django",
            Desc:"django标签",
        },
        {
            Name:"python",
            Desc:"python标签",
        },
        },
    }



ret := db.Create(&article)
fmt.Println(ret.Error)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

或者先插入单表的,再关联插入

tag := relate_tables.Tag{Name:"beego2",Desc:"beego2标签"}
db.Create(&tag)

article := relate_tables.Article2{
    Title:"测试多对多标题4",
    Content:"测试多对多内容5",
    Desc:"测试多对多描述5",
    Tags:[]relate_tables.Tag{
        tag,            
    },
}

db.Create(&article)       // 这里不会重复插入前面create的数据
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

二、查询

1.Preload

var article relate_tables.Article2

db.Preload("Tags").Find(&article,1)
fmt.Println(article)
  • 1
  • 2
  • 3
  • 4

2.Association

var article relate_tables.Article2
db.First(&article,1)

db.Model(&article).Association("Tags").Find(&article.Tags)
fmt.Println(article)
  • 1
  • 2
  • 3
  • 4
  • 5

3.Related

var article relate_tables.Article2
db.First(&article,1)

var tags []relate_table.Tag

db.Model(&article).Related(&tags, "Tags")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

三、更新

// 先查询
var article relate_tables.Article2
db.Preload("Tags").Find(&article,1)

// 再更新,记得加条件
db.Model(&article.Tags).Where("name = ?","beego").Update("name","xxx")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

四、删除

// 先查询
var article relate_tables.Article2
db.Preload("Tags").Find(&article,1)

// 再删除,记得加条件
db.Where("name = ?","xxx").Delete(&article.Tags)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

DB接口

First:

// 按照主键顺序的第一条记录,(主键升序)

var user model.User
result := db.First(&user)
fmt.Println(user)

result.RowsAffected // 返回找到的记录数
result.Error        // returns error

// sql语句:SELECT * FROM users ORDER BY id LIMIT 1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

FirstOrCreate

// 未找到 user,则根据给定条件创建一条新纪录
var user model.User
db.FirstOrCreate(&user, User{Name: "hallen"})

// 找到了 `name` = `hallen` 的 user
db.Where(User{Name: "hallen"}).FirstOrCreate(&user)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Last

// 获取最后一条记录(主键降序)
var user model.User
// 按照主键顺序的最后一条记录
db.Last(&user)
fmt.Println(user)

// sql语句:SELECT * FROM users ORDER BY id DESC LIMIT 1;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Take

// 获取一条记录,没有指定排序字段
var user model.User
db.Take(&user)

// sql语句:SELECT * FROM users LIMIT 1;
  • 1
  • 2
  • 3
  • 4
  • 5

Find

var user model.User

// 所有记录
db.Find(&users, []int{1,2,3})
// sql语句:// SELECT * FROM users WHERE id IN (1,2,3);

result := db.Find(&users)
// sql语句:SELECT * FROM users;

// 根据指定条件查询
db.Find(&user, "name = ?", "hallen")

//或者结合where
db.Where("name = ?", "hallen").Find(&users)
// sql语句:SELECT * FROM users WHERE name = 'hallen';

db.Where("name LIKE ?", "%ha%").Find(&users)
// sql语句:SELECT * FROM users WHERE name LIKE '%hal%';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Where

var user model.User


// 根据条件查询得到满足条件的第一条记录
db.Where("role_id = ?", "2").First(&user)
fmt.Println(user)

var users []model.User

// 根据条件查询得到满足条件的所有记录
db.Where("user_id = ?", "1").Find(&users)
fmt.Println(users)

// like模糊查询
db.Where("role_id like ?", "%2").Find(&users)
fmt.Println(users)

db.Where("updated_at > ?", "2019-02-08 18:08:27").Find(&users)
fmt.Println(users)

// struct结构查询条件
db.Where(&DqmUserRole{RoleId: "1,2", UserId: "1"}).First(&user)
fmt.Println(user)


条件:
=
LIKE
IN:Where("name IN ?", []string{"hallen", "hallen2"})
AND:Where("name = ? AND age >= ?", "jinzhu", "22")
Time:Where("updated_at > ?", lastWeek)
BETWEEN:Where("created_at BETWEEN ? AND ?", lastWeek, today)
  • 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
  • 32

Select

指定要从数据库检索的字段,默认情况下,将选择所有字段;

db.Select("name, age").Find(&users)
 SELECT name, age FROM users;

db.Select([]string{"name", "age"}).Find(&users)
 SELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()    // COALESCE:聚合
 SELECT COALESCE(age,'42') FROM users;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Create

1.插入单条

user := models.User{Name:"李四",Age:18,Addr:"xxx",Pic:"/static/upload/pic111.jpg",Phone:"13411232312"}
result := db.Create(&user)

user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.批量插入:暂不支持

user4 := []relate_tables.User{
        {
            Name:"hallen8",
            Age:18,
            Addr:"xxx",
        },
        {
            Name:"hallen9",
            Age:18,
            Addr:"xxx",
        },
    }

db.Create(&user4)    // 这种方式不支持
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

save

var user model.User

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

update

var users []model.User
db.Where("active = ?", true).find(&users).Update("name", "hello")


db.Where("active = ?", true).find(&users).Updates(User{Name: "hello", Age: 18})


// update也可以使用map:map[string]interface{}{"name": "hello", "age": 18}

// 也可以使用save更新
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

delete

db.Delete(&user,1)

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
  • 1
  • 2
  • 3
  • 4

Unscoped:软删除

    // 也就是逻辑删除    
    // gorm.Model 将DeletedAt 字段设置为当前时间
    // 需要再模型中指定

    type User struct {
      ID      int
      Deleted `gorm:"DeletedAt"`      // 如果设置了所有的删除都将是逻辑删除
      Name    string
    }

    // 在查询时会忽略被软删除的记录
    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(&user)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

Not

var user model.User

db.Not(User{Name: "hallen", Age: 18}).First(&user)

// SELECT * FROM `users`  WHERE (`users`.`name` <> 'hallen6') AND (`users`.`age` <> 19);
  • 1
  • 2
  • 3
  • 4
  • 5

Or

var users []model.User


db.Where("name = 'hallen'").Or(User{Name: "hallen2", Age: 18}).Find(&users)
// SELECT * FROM users WHERE name = 'hallen' OR (name = 'jinzhu 2' AND age = 18);
  • 1
  • 2
  • 3
  • 4
  • 5

Order

var users []model.User
db.Order("age desc").Find(&users) // 注意这里的order要在find前面,否则不生效
fmt.Println(users)

// SELECT * FROM users ORDER BY age desc;

默认为asc
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Limit和Offset

Limit 指定获取记录的最大数量 Offset 指定在开始返回记录之前要跳过的记录数量

var users []model.User


db.Limit(3).Find(&users)  // 三条
// SELECT * FROM users LIMIT 3;

db.Limit(10).Offset(5).Find(&users) // 从5开始的10条数据
// SELECT * FROM users OFFSET 5 LIMIT 10;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Scan

将结果扫描到另一个结构中。

type Result struct {
        Id int64
    }
var results []Result
db.Select("id").Where("user_id in (?)", []string{"1", "2"}).Find(&dqmUserRole20).Scan(&results)
fmt.Println(results)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Count

获取模型的记录数

db.Where("name = ?", "hallen").Find(&users).Count(&count)
// SELECT count(*) FROM users WHERE name = 'jinzhu'

db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)

db.Table("deleted_users").Count(&count)
// SELECT count(*) FROM deleted_users;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Group & Having

GROUP BY语句用来与聚合函数(aggregate functions such as COUNT, SUM, AVG, MIN, or MAX.)联合使用,只返回一个单个值

HAVING语句通常与GROUP BY语句联合使用,用来过滤由GROUP BY语句返回的记录集。

HAVING语句的存在弥补了WHERE关键字不能与聚合函数联合使用的不足

    type result struct {
      Date  time.Time
      Total int
    }

    db.Select("name, count(*)").Group("name").Find(&result)

    // select name,count(*) FROM users GROUP BY `age`

    db.Select("name, count(*)").Group("name").Having("add = ?","xxx").Find(&result)


  // select name,count(*) FROM users GROUP BY `age` 后面不能用where限制条件,只能使用having

 // select name,count(age) FROM users GROUP BY `age` HAVING addr='xxx'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Distinct:暂无

db.Distinct("name", "age").Order("name, age desc").Find(&results)
  • 1

Join

left join … on …

right join … on …

db.Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})
  • 1

高级查询

FirstOrInit和Attrs

FirstOrInit:获取第一个匹配的记录,或者使用给定的条件初始化一个新的记录(仅适用于struct,map条件)

Attrs:如果没有找到记录,则使用Attrs中的数据来初始化一条记录:

var user model.User

// 查不到该条记录,则使用attrs值替换,// 查到记录,则使用数据库中的值
db.Where(User{Name:"hallen"}).Attrs(User{Name:"hallen",Age:18}).FirstOrInit(&user)
  • 1
  • 2
  • 3
  • 4

FirstOrInit和Assign

Assign:不管是否找的到,最终返回结构中都将带上Assign指定的参数,有则代替,没有则添加

var user model.User

// 不管是否找到对应记录,使用Assign值替代查询到的值
db.Where("id = ?", "1").Assign(model.User{Id: "15"}).FirstOrInit(&user)
  • 1
  • 2
  • 3
  • 4

Pluck

Pluck 用于从数据库查询单个列,并将结果扫描到切片。如果您想要查询多列,您应该使用 Select 和 Scan

    var ages []int64
    db.Find(&users).Pluck("age", &ages)

    var names []string
    db.Model(&User{}).Pluck("name", &names)


    // 超过一列的查询,应该使用 `Scan` 或者 `Find`,例如:
    db.Select("name", "age").Scan(&users)
    db.Select("name", "age").Find(&users)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Scopes

Scopes 允许你指定常用的查询,可以在调用方法时引用这些查询

func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
  return db.Where("amount > ?", 1000)
}

func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
  return db.Where("pay_mode_sign = ?", "C")
}

func PaidWithCod(db *gorm.DB) *gorm.DB {
  return db.Where("pay_mode_sign = ?", "C")
}

func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
  return func (db *gorm.DB) *gorm.DB {
    return db.Where("status IN (?)", status)
  }
}

db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有金额大于 1000 的信用卡订单

db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// 查找所有金额大于 1000 的货到付款订单

db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// 查找所有金额大于 1000 且已付款或已发货的订单
  • 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

LogMode

Gorm有内置的日志记录器支持,默认情况下,它会打印发生的错误。

// 启用Logger,显示详细日志

db.LogMode(true)

// 也可以查看单语句的信息

db.Debug().Where("name = ?", "hallen").First(&User{})
  • 1

错误处理

如果在执行SQL查询的时候,出现错误,GORM 会将错误信息保存到 *gorm.DB 的Error字段,我们只要检测Error字段就可以知道是否存在错误。

一、处理单个错误

err := db.Where("name = ?", "tizi365").First(&user).Error
if err != nil {
  // 错误处理
}

// 或者

result := db.Where("name = ?", "jinzhu").First(&user)

if result.Error != nil {
  // 错误处理
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

二、处理多个错误

通过GetErrors获取错误列表

errors := db.First(&user).Limit(10).Find(&users).GetErrors()
fmt.Println(len(errors)) // 打印错误数量

// 遍历错误内容
for _, err := range errors {
  fmt.Println(err)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三、错误种类

gorm.错误类型进行判断,如gorm.ErrRecordNotFound

1.RecordNotFound:查询不到数据,不适用于切片

gorm.IsRecordNotFoundError(err) {
    // 没有查询到数据
}
  • 1
  • 2
  • 3

2.ErrInvalidSQL:无效sql

3.ErrInvalidTransaction:事务有错

4.ErrCantStartTransaction:无法开启事务,出现在使用Begin的情况下

5.ErrUnaddressable:使用不可寻址的值,传递的指针值不对

事务

用 db.Begin() 声明开启事务,结束的时候调用 tx.Commit(),异常的时候调用 tx.Rollback()

ct := db.Begin() // 开启事务
ret3 := ct.Commit()

if ret3.Error != nil {
    ct.Rollback()   // 回滚
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

复合主键

联合主键、组合主键

type Product struct {
    ID           int `gorm:"primary_key"`
    ERPID        int `gorm:"primary_key"`
}
  • 1
  • 2
  • 3
  • 4

原生sql

一、查询用Raw

var users []relate_tables.User
db.Raw("select * from users").Find(&users)
  • 1
  • 2

二、增改删用 Exec

db.Exec("insert into users (name,age) values(?,?)","hallen222",111)
db.Exec("update users set name = ? where id = ?","hallen111",1)
db.Exec("delete from  users where id = ?",1)
  • 1
  • 2
  • 3

三、返回单条

row,_ := db.Raw("select * from users").Row()
  • 1

四、返回多条

row,_ := db.Raw("select * from users").Rows()
  • 1

配置文件

一、配置信息:mysql.json

{
  "host":"localhost",
  "port":"3306",
  "user_name":"root",
  "password":"Qazwsx123",
  "database":"gin_project",
  "logo_mode":true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

二、加载配置文件

    package data_source

    import (
        "os"
        "io/ioutil"
        "encoding/json"
    )

    type MysqlConf struct {
        Host string `json:"host"`
        Port string `json:"port"`
        UserName string `json:"user_name"`
        Password string `json:"password"`
        DataBase string `json:"database"`
        LogoMode bool `json:"logo_mode"`
    }

    func LoadMysqlConf() *MysqlConf {

        mysql_conf := MysqlConf{}

        file,err := os.Open("conf/mysql.json")

        if err != nil {
            panic(err)
        }

        defer file.Close()

        byte_data,err2 := ioutil.ReadAll(file)

        if err2 != nil {
            panic(err2)
        }

        err3 := json.Unmarshal(byte_data,&mysql_conf)

        if err3 != nil {
            panic(err3)
        }


        return &mysql_conf

    }
  • 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
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

三、使用配置信息

package data_source

import (
    "github.com/jinzhu/gorm"
    "gin_project/models"
    _ "github.com/jinzhu/gorm/dialects/mysql"
    "fmt"
)

var Db *gorm.DB
var err error


func init() {

    mysql_conf := LoadMysqlConf()

    logo_mode := mysql_conf.LogoMode

    data_source := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
                mysql_conf.UserName,
                mysql_conf.Password,
                mysql_conf.Host,
                mysql_conf.Port,
                mysql_conf.DataBase,


        )


    Db,err = gorm.Open("mysql",data_source)

    if err != nil {
        panic(err)
    }

    Db.LogMode(logo_mode)


    Db.DB().SetMaxOpenConns(100) // 最大连接数
    Db.DB().SetMaxIdleConns(50) // 最大空闲数

    Db.AutoMigrate(&models.User{})
}
  • 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
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

代码示例抽取:

实现接口:D:\go\workspace\src\gin-vue-admin\common\datasource

base结构体:D:\go\workspace\src\gin-vue-admin\repository\BaseRepository.go

集成结构体:D:\go\workspace\src\gin-vue-admin\repository\UserRepository.go

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/457441
推荐阅读
相关标签
  

闽ICP备14008679号