gorm学习笔记
中文文档v1:jinzhu版: https://v1.gorm.io/zh_CN/docs/
中文文档v2:gorm.io版: https://gorm.io/zh_CN/
当前博客内容参考v1版本做的,v2版本与当前笔记可能会有所差别
安装GORM
go get -u github.com/jinzhu/gorm
连接数据库
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql" //引入mysql的驱动
)
// 同包下可以访问db参数
var db *gorm.DB
func main() {
var err error
//连接数据库:
//Open传入两个参数:
//第一个参数:指定你要连接的数据库
//第二个参数:指的是数据库的设置信息:用户名:密码@tcp(ip:port)/数据库名字?charset=utf8&parseTime=True&loc=Local
//charset=utf8设置字符集
//parseTime=True为了处理time.Time
//loc=Local 时区设置,与本地时区保持一致
db, err = gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
}
运行
如果运行中报错如下
missing go.sum entry for module providing package github.com/go-sql-driver/mysql (imported by github.com/jinzhu/gorm/dialects/mysql); to add:
执行如下命令即可解决
go get -u github.com/go-sql-driver/mysql
创建和删除表以及判断表是否存在
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// 定义结构体:
type User struct {
Age int
Name string
}
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
db.CreateTable(&User{})
//Table方法可以指定你要创建的数据库的表名
db.Table("user").CreateTable(&User{})
//删除表:
//db.DropTable(&User{}) //通过&User{}来删除users表
//db.DropTable("user") //通过"user"删除user表
//判断表是否存在:
flag1 := db.HasTable(&User{}) //判断是否有users表
fmt.Println(flag1)
flag2 := db.HasTable("user") //判断是否有user表
fmt.Println(flag2)
}
简单的增删改查
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
//定义结构体:
type User struct {
Age int
Name string
}
func main(){
//连接数据库:
db,err := gorm.Open("mysql","root:admin@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.Create(&User{Age:18,Name:"丽丽"})
//查询数据:第一个参数:查询出来的数据的载体:
var myuser User
db.First(&myuser,"age = ?",18)
fmt.Println(myuser)
//更新数据:
//需要做的:先查询,再更新
db.Model(&myuser).Update("age",30)
db.Model(&myuser).Update("name","菲菲")
//删除数据:
//需要做的:先查询,再删除
db.Delete(&myuser)
}
模型名与表名的映射
【1】模型名和表名的映射规则:
(1)如果模型名没有驼峰命名,那么表名就是:模型名小写+复数形式: 如模型名User-》表名users (2)如果模型名有驼峰命名,那么表名就是:大写变小写并在前面加下划线,最后加复数形式:如模型名UserInfo-》表名user_infos (3)如有模型名有连续的大写字母,那么表名就是:连续的大写字母变小写,驼峰前加下划线,字母变小写,最后加复数形式:如模型名:DBUserInfo-》表名db_user_infos
PS:模型中字段名称与表中列名的映射规则同上,学习视频中未曾演示,可自行练习使用
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:admin@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_匿名字段
【1】gorm.Model匿名字段 只需要在自己的模型中指定gorm.Model匿名字段,即可在数据库表中包含四个字段:ID,CreatedAt,UpdatedAt,DeletedAt
ID:主键自增长
CreatedAt:用于存储记录的创建时间
UpdatedAt:用于存储记录的修改时间
DeletedAt:用于存储记录的删除时间
【2】代码:
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type MyUser2 struct {
//增加一个匿名字段:
gorm.Model
Age int
Name string
}
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:
db.CreateTable(&MyUser2{})
}
结构体标签gorm
【1】通过结构体标签gorm来实现表的约束 【2】gorm标签属性值: (1)-: 忽略,不映射这个字段 eg: gorm:"-"
,适合:一些冗余字段,不想在数据库中体现,只想在结构体中体现 (2)primary_key:主键 eg: gorm:"primary_key"
PS:如果是想要加联合主键,在每个字段后加入 gorm:"primary_key"
即可 例如:即可将StuID和Name作为联合主键 (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:多个属性值之间用分号分隔
结构体代码
type Student struct {
StuID int `gorm:"primary_key;AUTO_INCREMENT"`
Name string `gorm:"not null"`
Age int `gorm:"unique_index"`
Email string `gorm:"unique"`
Sex string `gorm:"column:gender;size:10"`
Desc string `gorm:"-"`
Classno string `gorm:"type:int"`
}
多表操作
表关系
根目录下创建demostruct/demostruct.go
文件
一对一
demostruct.go
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
}
main.go
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type MyUser2 struct {
//增加一个匿名字段:
gorm.Model
Age int
Name string
}
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:
//创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
db.CreateTable(&demostruct.User{})
db.CreateTable(&demostruct.UserInfo{})
}
PS:并没有在数据库中强制加入外键,只是一种关联关系而已
【1】通过gorm标签来指定外键:(属于关系:关系和外键的指定在同一方)
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 `gorm:"ForeignKey:MyUserID;AssociationForeignKey:UserId"`
//指定外键:
MyUserID int
}
【2】通过gorm标签来指定外键:(包含关系:关系和外键的指定不在同一方)
package demostruct
type User struct{
UserId int `gorm:"primary_key;AUTO_INCREMENT"`
Age int
Name string
//指定外键:
IID int
}
type UserInfo struct {
InfoID int `gorm:"primary_key;AUTO_INCREMENT"`
Pic string
Address string
Email string
//关联关系
User User `gorm:"ForeignKey:IID;AssociationForeignKey:InfoID"`
}
一对多
demostruct.go
package demostruct
type Author struct {
AID int `gorm:"primary_key;AUTO_INCREMENT"`
Name string
Age int
Sex string
//关联关系:
Article []Article `gorm:"ForeignKey:AuId;AssociationForeignKey:AID"`
}
type Article struct {
ArId int `gorm:"primary_key;AUTO_INCREMENT"`
Title string
Content string
Desc string
//设置外键:
AuId int
}
main.go
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type MyUser2 struct {
//增加一个匿名字段:
gorm.Model
Age int
Name string
}
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:
db.CreateTable(&demostruct.Author{})
db.CreateTable(&demostruct.Article{})
}
多对多
demostruct.go
package demostruct
type Student struct {
SId int `gorm:"primary_key"`
SNo int
Name string
Sex string
Age int
//关联表:
Course []Course `gorm:"many2many:Student2Course"`
}
type Course struct {
CId int `gorm:"primary_key"`
CName string
TeacherName string
Room string
}
main.go
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type MyUser2 struct {
//增加一个匿名字段:
gorm.Model
Age int
Name string
}
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:
db.CreateTable(&demostruct.Student{})
db.CreateTable(&demostruct.Course{})
}
一对一操作
根目录下创建demostruct/demostruct.go
文件
关联添加
demostruct.go
package demostruct
type User struct{
UserId int `gorm:"primary_key;AUTO_INCREMENT"`
Age int
Name string
//指定外键:
IID int
}
type UserInfo struct {
InfoID int `gorm:"primary_key;AUTO_INCREMENT"`
Pic string
Address string
Email string
//关联关系
User User `gorm:"ForeignKey:IID;AssociationForeignKey:InfoID"`
}
main.go
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
db.CreateTable(&demostruct.User{})
db.CreateTable(&demostruct.UserInfo{})
//关联添加数据: (因为关联关系在UserInfo表中,所以添加操作从UserInfo来入手)
userinfo := demostruct.UserInfo{
Pic: "/upload/1.jpg",
Address: "北京海淀区",
Email: "124234@126.com",
User: demostruct.User{
Age: 19,
Name: "丽丽",
},
}
db.Create(&userinfo)
}
关联查询
Association方式(较麻烦,较繁琐)
Association方式查询缺点:先First查询,再Association查询,费劲
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
db.CreateTable(&demostruct.User{})
db.CreateTable(&demostruct.UserInfo{})
//关联添加数据: (因为关联关系在UserInfo表中,所以添加操作从UserInfo来入手)
//userinfo := demostruct.UserInfo{
// Pic: "/upload/1.jpg",
// Address: "北京海淀区",
// Email: "124234@126.com",
// User: demostruct.User{
// Age: 19,
// Name: "丽丽",
// },
//}
//db.Create(&userinfo)
//关联查询操作:(关联关系在UserInfo表中,所以从UserInfo入手)
var userinfo demostruct.UserInfo
//如果只是执行下面这步操作,那么关联的User信息是查询不到的:
db.First(&userinfo, "info_id = ?", 1)
// db.Debug().First(&userinfo, "info_id = ?", 1) // 通过Debug可以查看执行的具体sql语句
fmt.Println(userinfo) //{1 /upload/1.jpg 北京海淀区 124234@126.com {0 0 0}}
//如果想要查询到User相关内容,必须执行如下操作:
//Model参数:要查询的表数据,Association参数:关联到的具体的模型:模型名字User(字段名字)
//Find参数:查询的数据要放在什么字段中&userinfo.User
db.Model(&userinfo).Association("User").Find(&userinfo.User)
// db.Debug().Model(&userinfo).Association("User").Find(&userinfo.User) // 通过Debug可以查看执行的具体sql语句
fmt.Println(userinfo) //{1 /upload/1.jpg 北京海淀区 124234@126.com {1 19 丽丽 1}}
}
Preload方式
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//创建表:通常情况下,数据库中新建的标的名字是结构体名字的复数形式,例如结构体User,表名 users
db.CreateTable(&demostruct.User{})
db.CreateTable(&demostruct.UserInfo{})
//关联查询操作:(关联关系在UserInfo表中,所以从UserInfo入手)
var userinfo demostruct.UserInfo
//查询info_id=1的数据放入userinfo中,并关联查询到User字段对应的数据
db.Preload("User").Find(&userinfo, "info_id = ?", 1)
fmt.Println(userinfo) //{1 /upload/1.jpg 北京海淀区 124234@126.com {1 19 丽丽 1}}
}
Related方式
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联查询操作:(关联关系在UserInfo表中,所以从UserInfo入手)
var userinfo demostruct.UserInfo
db.First(&userinfo, "info_id = ?", 1)
fmt.Println(userinfo)
var user demostruct.User
//通过userinfo模型查出来的User字段的信息放入新的容器user中:
db.Model(&userinfo).Related(&user, "User")
fmt.Println(user)
fmt.Println(userinfo)
}
关联更新
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联更新
//先查询
var userinfo demostruct.UserInfo
db.Preload("User").Find(&userinfo, "info_id = ?", 1)
fmt.Println(userinfo)
//再更新:注意:Update的参数age可以用结构体中字段Age也可以用数据库age字段
db.Model(&userinfo.User).Update("age", 31)
fmt.Println(userinfo)
}
关联删除
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联删除
//先查询
var userinfo demostruct.UserInfo
db.Preload("User").Find(&userinfo, "info_id = ?", 1)
fmt.Println(userinfo)
//再删除:借助userinfo模型删除User记录
db.Delete(&userinfo.User) //UserInfo中信息没有被删除,删除的是关联的User表中的记录
db.Delete(&userinfo)
}
一对多操作
使用上面一对多的创建表的代码先创建数据表
关联添加
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type MyUser2 struct {
//增加一个匿名字段:
gorm.Model
Age int
Name string
}
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联添加:一对多关系,一个作者对应多个文章,关联关系在作者中,所以我们操作的模型是作者的模型:
author := demostruct.Author{
Name: "张三",
Age: 30,
Sex: "男",
Article: []demostruct.Article{
{
Title: "HTML入门",
Content: "HTML******",
Desc: "好的不得了",
},
{
Title: "CSS入门",
Content: "CSS******",
Desc: "好的不得了2",
},
},
}
db.Create(&author)
}
关联查询
Association
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联查询:
//Association方式查询:因为关联关系在Author中,所以我们操作的是Author模型
var author demostruct.Author
//如果只是执行下面这步操作,那么关联的Article信息是查询不到的:
db.First(&author, "a_id = ?", 1)
fmt.Println(author) //{1 张三 30 男 []}
//如果想要查询到Article相关内容,必须执行如下操作:
//Model参数:要查询的表数据,Association参数:关联到的具体的模型:模型名字Article(字段名字)
//Find参数:查询的数据要放在什么字段中&author.Article
db.Model(&author).Association("Article").Find(&author.Article)
fmt.Println(author) //{1 张三 30 男 [{1 HTML入门 HTML****** 好的不得了 1} {2 CSS入门 CSS****** 好的不得了2 1}]}
}
Preload
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联查询:
//Preload方式查询:
var author demostruct.Author
//查询a_id=1的数据放入author中,并关联查询到Article字段对应的数据
db.Preload("Article").Find(&author, "a_id = ?", 1)
fmt.Println(author) //{1 张三 30 男 [{1 HTML入门 HTML****** 好的不得了 1} {2 CSS入门 CSS****** 好的不得了2 1}]}
}
Related
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联查询:
//Preload方式查询:
//var author demostruct.Author
//查询a_id=1的数据放入author中,并关联查询到Article字段对应的数据
//db.Preload("Article").Find(&author,"a_id = ?",1)
//fmt.Println(author)//{1 张三 30 男 [{1 HTML入门 HTML****** 好的不得了 1} {2 CSS入门 CSS****** 好的不得了2 1}]}
//Related方式查询:
var author demostruct.Author
db.First(&author, "a_id = ?", 1)
fmt.Println(author) //{1 张三 30 男 []}
var as []demostruct.Article
//通过author模型查出来的Article字段的信息放入新的容器as中:
db.Model(&author).Related(&as, "Article")
fmt.Println(as) //[{1 HTML入门 HTML****** 好的不得了 1} {2 CSS入门 CSS****** 好的不得了2 1}]
fmt.Println(author) //{1 张三 30 男 []}
}
关联更新
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联更新:
//先查询
//Preload方式查询:
var author demostruct.Author
//查询a_id=1的数据放入author中,并关联查询到Article字段对应的数据
db.Preload("Article").Find(&author, "a_id = ?", 1)
fmt.Println(author) //{1 张三 30 男 [{1 HTML入门 HTML****** 好的不得了 1} {2 CSS入门 CSS****** 好的不得了2 1}]}
//再更新:
//如果直接Update操作那么关联的文章的记录就会被全部更改
//db.Model(&author.Article).Update("title","JS入门")
//所以你要改动指定的记录必须加入限定条件:
db.Model(&author.Article).Where("ar_id = ?", 1).Update("title", "JS入门")
}
关联删除
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联删除:
//先查询
//Preload方式查询:
var author demostruct.Author
//查询a_id=1的数据放入author中,并关联查询到Article字段对应的数据
db.Preload("Article").Find(&author, "a_id = ?", 1)
fmt.Println(author) //{1 张三 30 男 [{1 HTML入门 HTML****** 好的不得了 1} {2 CSS入门 CSS****** 好的不得了2 1}]}
//再删除:必须加入指定条件
db.Where("ar_id = ?", 2).Delete(&author.Article)
}
多对多操作
使用上面多对多的创建表的代码先创建数据表
关联添加
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//关联添加操作:关联关系在Student中,所以我们模型操作的也是Student:
stu := demostruct.Student{
SNo: 1001,
Name: "丽丽",
Sex: "女",
Age: 18,
Course: []demostruct.Course{
{
CName: "c++",
TeacherName: "张三",
Room: "s-103",
},
{
CName: "高数",
TeacherName: "李四",
Room: "s-801",
},
},
}
db.Create(&stu)
}
事务处理
用 db.Begin() 声明开启事务,结束的时候调用 tx.Commit(),异常的时候调用 tx.Rollback()
常用方法
使用上面一对一操作
里面的结构体和关联添加创建完数据表和字段后再看下面的代码
【1】First:按照条件查询,并且升序排列,查询出一条记录
【2】FirstOrCreate:有数据就查询出来,没有就创建一条记录
【3】Last:按照条件查询,并且降序排列,查询出一条记录
【4】Take:按照条件查询,查询出一条记录
【5】Find:按照条件查询
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//First:
var user demostruct.User
//First:SELECT * FROM `users` WHERE (`users`.`user_id` = 1) ORDER BY `users`.`user_id` ASC LIMIT 1
//db.Debug().First(&user,1) -->默认情况查询的是主键
//fmt.Println(user)
//对应SQL:SELECT * FROM `users` WHERE (user_id = 1) ORDER BY `users`.`user_id` ASC LIMIT 1
//db.Debug().First(&user,"user_id = ?",1)
//fmt.Println(user)
//对应SQL:SELECT * FROM `users` WHERE (user_id = 1) ORDER BY `users`.`user_id` ASC LIMIT 1
//db.Debug().Where("user_id = ?",1).First(&user)
//fmt.Println(user)
//FirstOrCreate
//user2 := demostruct.User{//这里定义的结构体的实例的数值其实就是FirstOrCreate的查询条件
// UserId: 2,
// Age: 20,
// Name: "菲菲",
// IID: 1,
//}
//如果有对应的数据,就查询出来,如果没有对应的数据,就会帮我们创建新的记录
//db.FirstOrCreate(&user,user2)
//fmt.Println(user)
//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:对应SQL: SELECT * FROM `users` WHERE (`users`.`user_id` = 1) LIMIT 1
//db.Debug().Take(&user,1)
//fmt.Println(user)
//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....
【7】Select:筛选查询出来的字段
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
var user demostruct.User
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//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)
db.Debug().Select("name,age").Where("user_id = ?", 1).First(&user)
fmt.Println(user) //{0 19 丽丽 0}
}
【8】Create:添加数据
【9】Save:添加数据
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//Create操作只可以插入一条技能,不能批量操作
//user := demostruct.User{
// Age: 26,
// Name: "小明",
// IID: 1,
//}
//
//db.Create(&user)
user := demostruct.User{
Age: 14,
Name: "莎莎",
IID: 1,
}
db.Save(&user)
}
【10】Update:更新数据
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//更新:先查询再更新:
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": "小花",
})
}
【11】Delete:删除数据
package main
import (
"demo01/demostruct"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//Delete:删除数据:
// (1)先查询再删除:
//var user demostruct.User
//db.Where("user_id = ?",1).First(&user)
//db.Delete(&user)
//(2)通过条件直接进行删除:
var user demostruct.User
db.Where("user_id = ?", 2).Delete(&user)
}
【12】Not:排除某个具体条件的查询操作
【13】Or:多个条件的查询
【14】Order:进行升序或者降序的排列
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//Not:
//var users []demostruct.User
//db.Not("user_id = ?",1).Find(&users)
//fmt.Println(users)
//对应SQL:SELECT * FROM `users` WHERE (`users`.`age` <> 18) AND (`users`.`name` <> '丽丽')
//var users []demostruct.User
//db.Debug().Not(demostruct.User{
// Age: 18,
// Name: "丽丽",
//}).Find(&users)
//fmt.Println(users)
//Or :
//var users []demostruct.User
//db.Where("user_id = ?",1).Or("user_id = ?",3).Find(&users)
//fmt.Println(users)
//Order:
var users []demostruct.User
db.Where("age = ?", 14).Order("user_id asc").Find(&users)
fmt.Println(users)
}
【15】Limit:指定获取记录的最大数量
【16】Offset:设置偏移
【17】Scan:将结果扫描到另一个结构体中
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db,err := gorm.Open("mysql","root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//Limit:
//var users []demostruct.User
//db.Limit(2).Find(&users)
//fmt.Println(users)
//Offset:
//注意:Offset中设置的偏移数字为第几条记录,从0开始,0、1、2、、、、
//注意:Offset必须和Limit结合使用
//var users []demostruct.User
//db.Offset(1).Limit(2).Find(&users)
//fmt.Println(users)
//Scan
type UserDemo struct {//你要扫描的结构体的字段的名字和User中的字段名字必须一致才可以扫描
Name1 string
Age int
}
var userdemo UserDemo
var user demostruct.User
db.Where("user_id=?",1).Find(&user).Scan(&userdemo)
fmt.Println(user)
fmt.Println(userdemo)
}
【18】Count:计数
【19】GROUP:进行分组
【20】Having:分组后进行过滤
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//Count:
//var users []demostruct.User
//定义一个变量接收计数的数量:
//var count int
//db.Find(&users).Count(&count)
//fmt.Println(users)
//fmt.Println(count)
//Group:
var users []demostruct.User
//定义一个新的结构体:
type GroupData struct {
Age int
Count int
}
var group_date []GroupData
//对应SQL:SELECT age,count(*) FROM `users` GROUP BY age
//对应SQL:SELECT age,count(*) as count FROM `users` GROUP BY age HAVING (age > 18)
//Having:在分组以后进行过滤
db.Debug().Select("age,count(*) as count").Group("age").Find(&users).Having("age > 18").Scan(&group_date)
fmt.Println(users)
fmt.Println(group_date)
}
【21】Join :左连接、右连接:
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//Joins:
//定义一个新的结构体用于Scan:
type NewUserInfo struct {
User_Id int
Name string
I_Id int
Info_Id int
Address string
}
var newUser []NewUserInfo
var users []demostruct.User
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)
fmt.Println(users)
fmt.Println(newUser)
}
【22】LogMod: Gorm内置的日志记录器,显示详细日志
PS :利用Debug只能逐条打印对应日志信息,但是设置LogMod(true)相当于设置了全局打印,所有执行的逻辑日志都会帮我们输出打印
package main
import (
"demo01/demostruct"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//开启打印日志:
db.LogMode(true)
//Joins:
//定义一个新的结构体用于Scan:
type NewUserInfo struct {
User_Id int
Name string
I_Id int
Info_Id int
Address string
}
var newUser []NewUserInfo
var users []demostruct.User
db.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)
fmt.Println(users)
fmt.Println(newUser)
}
支持原生sql
package main
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//开启打印日志:
db.LogMode(true)
//查询操作: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)
}
日志的引入
概述
【1】日志的重要性及作用: 日志是程序的重要组成部分 1.记录用户操作的审计日志 2.快速定位问题的根源 3.追踪程序执行的过程。 4.追踪数据的变化 5.数据统计和性能分析 6.采集运行环境数据 . 【2】第三方日志库: Golang标准库的日志框架非常简单,仅仅提供了print,panic和fatal三个函数,对于更精细的日志级别、日志文件分割以及日志分发等方面并没有提供支持。 所以催生了很多第三方的日志库,但是在golang的世界里,没有一个日志库像slf4j那样在Java中具有绝对统治地位。golang中,流行的日志框架包括logrus、zap、zerolog、seelog等。 logrus是目前Github上star数量最多的日志库,logrus功能强大,性能高效,而且具有高度灵活性,提供了自定义插件的功能。很多开源项目,如docker,prometheus等,都是用了logrus来记录其日志。
Logrus的使用
【1】下载Logrus第三方库: 录入安装Logrus的命令:
go get -u github.com/sirupsen/logrus
【2】单独提取配置文件:
根目录下创建confs/log_config.json
文件,内容如下:
{
"log_dir": "d:mylog.log",
"log_level": "info"
}
【3】加载配置文件:
根目录下创建logs_ope/log_load_conf.go
文件,内容如下:
package logs_ope
import (
"encoding/json"
"io/ioutil"
"os"
)
//对应结构体:
type LogConfig struct {
LogDir string `json:"log_dir"`
LogLevel string `json:"log_level"`
}
//读取配置文件:
func LoadLogConfig() *LogConfig{
log_conf := LogConfig{}
//打开文件:
file,err := os.Open("confs/log_config.json")
if err != nil{//错误处理
panic(err)
}
//资源释放:
defer file.Close()
//用流读取文件中内容:
data,err2 := ioutil.ReadAll(file)
if err2 != nil {
panic(err2)
}
//Unmarshal将json字符串解码到对应的数据结构中:
//第一个参数:json字符串,第二个参数:接收json解析的数据结构
err3 := json.Unmarshal(data,&log_conf)
if err3 != nil {
panic(err3)
}
return &log_conf
}
【4】初始化日志记录器实例:
新建logs_ope/log_init.go
文件,内容如下:
package logs_ope
import (
"github.com/sirupsen/logrus"
"os"
)
//初始化记录器一个实例:
var Logrus = logrus.New()
func init(){
//先读取日志的配置文件:
log_conf := LoadLogConfig()
//设置日志的输出文件:
file,err := os.OpenFile(log_conf.LogDir,os.O_APPEND|os.O_CREATE,0666)
if err != nil {
panic(err)
}
//将上面打开的file文件设置为 日志的输出文件:
Logrus.Out = file
//设置日志的级别:
//定义一个map,专门存储日志级别:
log_level_map := map[string]logrus.Level{
"trace" : logrus.TraceLevel,
"panic": logrus.PanicLevel,
"fatal": logrus.FatalLevel,
"error": logrus.ErrorLevel,
"warn": logrus.WarnLevel,
"info": logrus.InfoLevel,
"debug": logrus.DebugLevel,
}
Logrus.SetLevel(log_level_map[log_conf.LogLevel])
//日志格式化:设置文本格式
Logrus.SetFormatter(&logrus.TextFormatter{})
}
【5】在main.go中加载init函数:
package main
import (
_ "demo01/logs_ope"
)
func main() {
}
【6】在具体的逻辑中可以使用日志记录器:
在根目录下创建stuope/stuope.go
,内容如下:
package main
import (
"demo01/logs_ope"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
func main() {
//连接数据库:
db, err := gorm.Open("mysql", "root:admin@tcp(localhost:3306)/testgorm?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err) //如果出错,后续代码没有必要执行,想让程序中断,panic来执行即可
}
//数据库资源释放:
defer db.Close()
//开启打印日志:
db.LogMode(true)
// 日志记录操作
logs_ope.Logrus.Info("向数据库中增加了一条记录")
}
运行项目,查看本地对应的日志信息打印