gorm
本人这段时间在学习go语言,以下是学习过程中写的gorm笔记,一方面是自己学习的总结,一方面也想与大家分享观点。
基础操作
结构体标签
常用方法
最基础操作
连接,建表,删表,判断是否存在等等
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql" //引入mysql驱动
)
// 定义结构体
type User struct {
Age int
Name string
}
func main() {
//连接数据库:
//Open传入两个参数:
//第一个参数:指定你要连接的数据库
//第二个参数:指的是数据库的设置信息:
//用户名:密码@tcp(ip:port)/数据库名字?charset=utf8&parseTime=True&loc=Local
//charset=utf8设置字符集
//parseTime=True是为了处理time.Time
//loc=Local时区设置
db, err := gorm.Open("mysql", "root:1234@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
defer db.Close()
//创建表:通常情况下数据库中新建的名字是结构体名字的复数形式,例如结构体User。表users
//db.CreateTable(&User{})
//db.Table("user").CreateTable(&User{})
db.DropTable(&User{}) //通过&User{}删除users表
db.DropTable("user") //通过“user”删除user表
//判断表是否存在
flag1 := db.HasTable(&User{})
fmt.Println(flag1)
flag2 := db.HasTable("user")
fmt.Println(flag2)
}
进行增删改操作
增加
//增加
//db.Create(&User{Age: 18, Name: "丽丽"}) //
相关函数:
//db.First()是GORM(Go语言的ORM库)中的一个函数,用于从数据库中 查询并返回第一条记录。
//它的作用是根据指定的条件,按照默认的排序规则从数据库中查询匹配的第一条记录。
db.First(&result, "condition")
其中,`&result`表示查询结果将会存储在`result`变量中,`"condition"`表示查询条件。
查询
//查询:需要查询出来数据的载体,即查询的数据需要有东西存放
var myuser User //定义myuser来存放数据
db.First(&myuser, "age= ?", 18)
fmt.Println(myuser)
修改或更新数据:
前提是你已经有载体把原来的数据放起来了
意思是说:需要更新数据就得先查询,在更新
db.Model(&myuser).Update("age", 30)
db.Model(&myuser).Update("name", "绯绯")
删除数据:
//删除数据:
//需要做的:先查询,再删除
db.Delete(&myuser)
模型名和表名映射
上文已经讲了数据库对象会以大写字母小写,尾部复数的形式出现在数据库中,下边是详细的映射规则
- (1)如果模型名没有驼峰命名,那么表名就是:模型名小写+复数形式: 如模型名User-》表名users
- (2)如果模型名有驼峰命名,那么表名就是:大写变小写并在前面加下划线,最后加复数形式:如模型名UserInfo-》表名user_infos
- (3)如有模型名有连续的大写字母,那么表名就是:连续的大写字母变小写,驼峰前加下划线,字母变小写,最后加复数形式:如模型名:DBUserInfo->>>表名db_user_infos
代码示例:
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
//定义结构体:
type User struct {
Age int
Name string
}
type UserInfo struct {
Age int
Name string
}
type DBUserInfo struct {
Age int
Name string
}
type MyUser struct {
Age int
Name string
}
func (MyUser) TableName() string{
return "test_my_user"
}
func main(){
//连接数据库:
db,err := gorm.Open("mysql","root:root@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
db.CreateTable(&User{})
db.CreateTable(&UserInfo{})
db.CreateTable(&DBUserInfo{})
db.CreateTable(&MyUser{})
}
gorm.Model匿名字段
目的是为了简化操作
只需要在自己的模型中指定gorm.Model匿名字段,即可在数据库表中包含四个字段:ID,CreatedAt,UpdatedAt,DeletedAt
自动生成四个能用上的字段
ID:主键自增长
CreatedAt:用于存储记录的创建时间
UpdatedAt:用于存储记录的修改时间
DeletedAt:用于存储记录的删除时间
示例:
// 定义结构体:
type User struct {
gorm.Model //匿名字段
Age int
Name string
}
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:1234@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
db.CreateTable(&User{})
}
结构体标签gorm:" "
就是用go来代替mysql的建表语句
先上示例:
type Student struct {
StuID int `gorm:"primary_key;AUTO_INCREMENT"`
使用primary_key标签指定它为主键,AUTO_INCREMENT标签表示它是自增的。
Name string `gorm:"not null"`
//这个字段用于表示学生的姓名,使用not null标签指定它不能为空。
Age int `gorm:"unique_index"`
//使用unique_index标签指定它是唯一索引,即每个年龄值只能出现一次。
Email string `gorm:"unique"`
//使用unique标签指定它必须是唯一的,即每个邮箱只能出现一次。
Sex string `gorm:"column:gender;size:10"`
//这个字段用于表示学生的性别,使用column标签指定它在数据库中的列名为gender即结构体中和数据库中名字不同,但表示同一数据,size标签指定它的长度为10
Desc string `gorm:"-"`
//用于表示学生的描述信息,使用了-标签,表示在数据库中不需要映射此字段,即只在代码中有,数据库没有
Classno string `gorm:"type:int"`
//这个字段用于表示学生的班级编号,使用type标签指定它的数据类型为int。
}
相信学过数据库的一眼就能认出很多,以下是全部标签
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
通过结构体标签gorm来实现表的约束
【2】gorm标签属性值:
(1)-: 忽略,不映射这个字段 eg: gorm:"-"
,适合:一些冗余字段,不想在数据库中体现,只想在结构体中体现
(2)primary_key:主键 eg: gorm:"primary_key"
PS:如果是想要加联合主键,在每个字段后加入 gorm:"primary_key"
即可
例如:即可将StuID和Name作为联合主键
StuID int gorm:"primary_key"
Name string gorm:"primary_key"
(3)AUTO_INCREMENT:自增 eg: gorm:"AUTO_INCREMENT"
(4)not null:不为空,默认为空 eg: gorm:"not null"
(5)index:索引, eg: gorm:"index"
创建索引并命名:eg: gorm:"index:idx_name_code"
(6)unique_index:唯一索引 eg: gorm:"unique_index"
唯一性索引unique index和一般索引normal index最大的差异就是在索引列上增加了一层唯一约束。添加唯一性索引的数据列可以为空,但是只要存在数据值,就必须是唯一的。
(7)unique:唯一 eg: gorm:"unique"
(8)column:指定列名 eg: gorm:"column:user_name"
(9)size:字符串长度,默认为255 eg:gorm:"size:10"
(10)default default:'男'
默认值
(11)type:设置sql类型 eg: gorm:"type:int(2)"
PS:多个属性值之间用分号分隔
表关系
示例:
结构体User,UserInfo:
package demostruct
type User struct{
UserId int `gorm:"primary_key;AUTO_INCREMENT"`
Age int
Name string
}
type UserInfo struct {
InfoID int `gorm:"primary_key;AUTO_INCREMENT"`
Pic string
Address string
Email string
//关联关系
User User
//指定外键
UserId int
}
Association方式查询,先First查询,再Associaion查询,费劲
//db.Model(&userinfo).Association("User").Find(&userinfo.User)
//fmt.Println(userinfo)
//{1 /upload/1.jpg 北京海淀区 124234@126.com {1 19 丽丽 1}}
Proload方式查询:通常会用这个,更方便
db.Preload("User").Find(&userinfo, "info_id=?", 1)
fmt.Println(userinfo)
//{1 /upload/1.jpg 北京海淀区 124234@126.com {1 19 丽丽 1}}
Related
var user demostruct.User
//拖过userinfo模型查出来的User字段放到新的容器user中:
db.Model(&userinfo).Related(&user, "User")
fmt.Println(user)
fmt.Println(userinfo)
//{1 19 丽丽 1}
//{1 /upload/1.jpg 北京海淀区 124234@126.com {0 0 0}}
Ps:查出的数据是分开存放的
通过UserInfo表数据对User表中数据进行更新
// 创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
var userinfo demostruct.UserInfo
db.Preload("User").Find(&userinfo, "info_id=?", 1)
fmt.Println(userinfo)
//再更新:注意:Update的参数age可以用结构体中字段,也可以用数据库字段
db.Model(&userinfo.User).Update("age", 31)
fmt.Println(userinfo)
删除
db.Delete()
一对多多对多
gorm中常用方法(命令):
包含各种建表查询删除的常用方法
- 【1】First:按照条件查询,并且升序排列,查询出一条记录
- 【2】FirstOrCreate:有数据就查询出来,没有就创建一条记录
- 【3】Last:按照条件查询,并且降序排列,查询出一条记录
- 【4】Take:按照条件查询,查询出一条记录
2,3,4在通常结果是一样的,需要打印sql语句才能看出区别
- 【5】Find:按照条件查询:可以同时查多个
下边是这五个方法的示例:
First
//db.Debug().First(&user, "user_id=?", 1)
// SELECT * FROM `users` WHERE (user_id=1) ORDER BY `users`.`user_id` ASC LIMIT 1
//其实效果和
db.Debug().First(&user, 1) //是一样的:
//SELECT * FROM `users` WHERE (`users`.`user_id`
// = 1) ORDER BY `users`.`user_id` ASC LIMIT 1
fmt.Println(user)
FirstOrCreate
//FirstOrCreate
//user2 := demostruct.User{//这里定义的结构体的实例的数值其实就是FirstOrCreate的查询条件
// UserId: 2,
// Age: 20,
// Name: "菲菲",
// IID: 1,
//}
//如果有对应的数据,就查询出来,如果没有对应的数据,就会帮我们创建新的记录
//db.FirstOrCreate(&user,user2)
//fmt.Println(user)
Last
//Last:对应SQL:SELECT * FROM `users` WHERE (`users`.`user_id` = 1) ORDER BY `users`.`user_id` DESC LIMIT 1
//db.Debug().Last(&user,1)
//fmt.Println(user)
Take
//Take:对应SQL: SELECT * FROM `users` WHERE (`users`.`user_id` = 1) LIMIT 1
//db.Debug().Take(&user,1)
//fmt.Println(user)
Find
//Find:对应SQL:SELECT * FROM `users` WHERE (`users`.`user_id` = 1)
user_id_arr := []int{1,2}
db.Debug().Find(&user,user_id_arr)//SELECT * FROM `users` WHERE (`users`.`user_id` IN (1,2))
fmt.Println(user)
- 【6】Where:加入指定条件:具体条件为:=,like,in,and,between…:where后的括号中参数和语句必须分开写
- 【7】Select:筛选查询出来的字段
where
//db.Debug().Where("user_id = ?",1).First(&user)//没加条件的
//fmt.Println(user)
//db.Debug().Where("user_id in (?)",[]int{1,2}).First(&user)
//fmt.Println(user)//加条件的
select
db.Debug().Select("name,age").Where("user_id = ?",1).First(&user)
fmt.Println(user)//{0 19 丽丽 0}
select不写默认全查,写了就只查写的
- 【8】Create:添加数据
- 【9】Save:添加数据
Create
//Create操作只可以插入一条记录,不能批量操作
//user := demostruct.User{
// Age: 26,
// Name: "小明",
// IID: 1,
//}
//
//db.Create(&user)
Save
user := demostruct.User{//可以批量添加
Age: 14,
Name: "莎莎",
IID: 1,
}
db.Save(&user)
Update
更新数据:必须先查询放到参数中才能在更新
//更新:先查询再更新:
var user demostruct.User
//(1)先查询,再通过Model进行操作,再Update操作:
//db.Where("user_id = ?",1).First(&user)
//db.Model(&user).Update("age",29)
//(2)直接在查询之后进行操作:
db.Where("user_id = ?",1).First(&user).Update("name","露露")
//(3)直接在查询之后进行操作,传入结构体示例,更新多个字段
db.Where("user_id = ?",1).First(&user).Update(demostruct.User{
Age: 11,
Name: "小刚",
})
//(4)直接在查询之后进行操作,传入map,更新多个字段
db.Where("user_id = ?",1).First(&user).Update(map[string]interface{}{
"age" : 21,
"name" : "小花",
})
四选一就行了,结果都是一样的,第二个就挺不错
Delete
删除数据
//Delete:删除数据:
// (1)先查询再删除:
//var user demostruct.User
//db.Where("user_id = ?",1).First(&user)
//db.Delete(&user)
删除id=1的数据
//(2)通过条件直接进行删除:
var user demostruct.User
db.Where("user_id = ?",2).Delete(&user)
删除id=2的数据
第二个更简单
Not
Not
方法用于创建一个条件,表示某个条件的相反条件。
-
例如,如果你有一个查询条件为
db.Where("name = ?", "John")
,你可以使用Not
来获取名字不是 “John” 的记录:db.Not("name = ?", "John")
。 -
db.Not("name = ?", "John").Find(&users)
Or
可以将多个条件连接在一起
db.Where("name = ?", "John").Or("age > ?", 25)
查询名字为 "John" 或者年龄大于 25 岁的用户记录
Order
用于指定查询结果的排序顺序
// 按照名字降序排列
db.Order("name desc").Find(&users)
limit
指定获取数据的最大数量
// 示例:限制查询结果为10条记录
db.Limit(10).Find(&users)
Offset
用于指定从查询结果的哪一行开始返回记录。
// 示例:从第6条记录开始返回结果
db.Offset(5).Find(&users)
Scan
Scan
方法用于将查询结果扫描到指定的结构体中。- 通常在执行查询后,使用
Scan
将结果映射到相应的Go结构体。
// 示例:将查询结果映射到User结构体中,容易输出和使用
var user User
db.Where("name = ?", "John").First(&user).Scan(&user)
count
Count
方法用于计算符合指定条件的记录总数。- 例如,
db.Model(&User{}).Where("age > ?", 18).Count(&count)
将返回满足条件的年龄大于 18 的用户记录总数,并将结果存储在count
变量中。
// 示例:计算年龄大于18的用户记录总数
var count int64
db.Model(&User{}).Where("age > ?", 18).Count(&count)
简例:查询有多少条数据
var user []demostruct.User//定义
var count int //定义count存放数量
db.Find(&user).Count(&count) //用FInd查询数据的数量
fmt.Println(user) //[{1 19 露露 1} {2 20 绯绯 1} {3 23 拉拉 2}]
fmt.Println(count) //3
group
Group
方法用于指定查询结果的分组方式。- 例如,
db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Find(&result)
将按订单状态分组,并返回每个状态的订单数量。
// 示例:按订单状态分组,并返回每个状态的订单数量
var result []struct {
Status string
Count int
}
db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Find(&result)
简例:按不同年龄分类,并返回不同年龄人的数量
var user []demostruct.User
type data struct {
Age int
Count int
}
var c []data
db.Debug().Select("age,count(*) as count").Group("age").Find(&user).Scan(&c)
fmt.Println(user)
fmt.Println(c)
输出:
[{0 19 0} {0 23 0}]
[{19 2} {23 1}]
having
Having
方法用于在分组的基础上进一步过滤数据。- 例如,
db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Having("COUNT(*) > ?", 10).Find(&result)
将返回订单数量大于 10 的每个状态。
// 示例:返回订单数量大于10的每个状态
var result []struct {
Status string
Count int
}
db.Model(&Order{}).Select("status, COUNT(*)").Group("status").Having("COUNT(*) > ?", 10).Find(&result)
简例 :在group基础上分组,筛选出年龄大于18的
db.Debug().Select("age,count(*) as count").
Group("age").Find(&user).Having("age>18").Scan(&c)
fmt.Println(user)
fmt.Println(c)
输出:
[{0 19 0} {0 23 0}]
[{23 1}]
Join
Join 用于在查询中关联其他表的数据,最常用的方法是joins
先上示例:
type NewUserInfo struct {//定义新的结构体用于scan,存储 Join 后的结果。
User_Id int
Name string
I_Id int
Info_Id int
Address string
}
var newUser []NewUserInfo// 创建一个切片,用于存储 Join 操作后的结果集
var users []demostruct.User//创建一个切片,用于存储查询 users 表的结果集。
db.Debug().Select("users.user_id,users.name,users.i_id,user_infos.info_id,user_infos.address").Joins("left join user_infos on users.i_id = user_infos.info_id").Find(&users).Scan(&newUser)
//逐个分析:前一部分使用 Select 方法指定了要查询的字段,
后半部分使用Joins方法关联了 users 表和 user_infos 表,关联条件为:users.i_id =user_infos.info_id。
Find(&users): 执行查询操作,将结果存储到 users 切片中。
Scan(&newUser): 将查询结果映射到 newUser 切片中的 NewUserInfo 结构体。
fmt.Println(users)
fmt.Println(newUser)
这段代码使用 GORM 进行 JOIN 操作,关联了 users 表和 user_infos 表,最后将结果映射到一个新的结构体 NewUserInfo 和一个切片 newUser 中。
logmod
Gorm内置的日志记录器,显示详细日志
PS :利用Debug只能逐条打印对应日志信息,但是设置LogMod(true)相当于设置了全局打印,所有执行的逻辑日志都会帮我们输出打印
//开启打印日志:
db.LogMode(true)
原生sql语句:
//查询操作:Raw
//var users []demostruct.User
//db.Raw("select * from users where age = ?",14).Find(&users)
//fmt.Println(users)
//增加、删除、修改 :Exec
//db.Exec("insert into users (age,name) values (?,?)",33,"莹莹")
//db.Exec("delete from users where user_id = ?",1)
//db.Exec("update users set name = ? where user_id = ?","明明",3)
大致就是这些,欢迎一起讨论学习