1.安装GORM
- 将GO语言的环境变量GOPATH配置好,之后下载的库都会下载到GOPATH这里,可以在GOPATH这个环境变量下的路径的mod下找到 在终端执行这两行命令
go get -u gorm.io/gormgo get -u gorm.io/driver/mysql
2.创建一个mysql数据库
- 终端打开mysql window下可以打开powershell 然后输入 mysql -u root -p 然后输入密码就可以登入mysql数据库
- 创建一个新的数据库 godb
CREATE DATABASE godb
3. 使用GORM连接数据库
- 在go文件中创建一个产品结构体 Product
type Product struct {
gorm.Model
Code string
Price string
}
var p Product
var products []Product
看到gorm.Model中的结构是
type Model struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt DeletedAt `gorm:"index"`
}
可以看到其中有创建时间和更新时间和删除标记
2. 连接数据库
1.定义dsnMySQL 数据库连接字符串,数据库的端口,连接数据库名,charset字段设置为utf8m64支持表情符号等字符,
parseTime=True表示将数据库中的日期/时间字段(如 DATETIME 或 TIMESTAMP)自动解析为 Go 的 time.Time 类型
loc=Local:指定时区为本地时区
dsn := "username:password@tcp(127.0.0.1:3306)/godb?charset=utf8mb4&parseTime=True&loc=Local"
- 然后连接数据库,使用
db.AutoMigrate(&Product{}),会根据结构体的字段和标签来判断如何创建或更新数据库中的表。如果表不存在,GORM 会创建它;如果表已经存在,GORM 会尝试根据结构体的字段修改表的结构(比如添加新的字段、修改字段类型等)。
db,err := gorm.Open(mysql.Open(dsn),&gorm.Config{})
if err != nil{
fmt.Println("gorm.Open failed",err)
panic(err)
}
db.AutoMigrate(&Product{})
可以看到这里已经创建了表,并且结构也是我们定义的
4. 使用GORM对数据库增删改查
使用GORM库创建
1. 定义一个表,然后创建表
p1 := &Product{
Code: "C23",
Price: 100 ,
}
db.Create(p1)
创建一个指向 Product 结构体实例的指针切片,使用Create() 创建多项记录。使用指针 (*Product) 可以避免拷贝结构体,且允许修改原始数据。
product := []*Product{
{Code: "A12", Price: 20},
{Code: "B34", Price: 50},
{Code: "C12", Price: 20},
{Code: "D34", Price: 50},
}
db.Create(product)
2. 使用GORM库进行查询操作
1. 使用First()根据主键检索
按主键查询,使用First()用来查询数据库中指定条件匹配的第一条记录,这里指定主键为1.
First(dest interface{}, conds ...interface{})第一个值传入结构体指针,查询后的值会传入到这个结构体中,第二个值传入
var p Product
db.First(&p,1)
fmt.Printf("p:%#v\n",p)
输出结果如下:
p:main.Product{Model:gorm.Model{ID:0x1, CreatedAt:time.Date(2024, time.November, 25, 17, 51, 55, 859000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 17, 51, 55, 859000000, time.Local), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, Code:"C23", Price:0x64}
如果主键是字符串(例如像uuid),查询将被写成如下:
db.First(&user, "id = ?", "1b74413f-f3b8-409f-ac47-e8c062e3472a")
2. 使用Find()检索
直接使用db.Find()的话,相当于在mysql中使用SELECT * FROM users;
定义一个变量products为结构体切片,然后使用db.Find(&products),查询表中全部元素,会返回一个(tx *gorm.DB)对象
var products []Product
result := db.Find(&products)
fmt.Printf("len:%#v\n",result.RowsAffected)
fmt.Printf("err:%#v\n",result.Error)
result.RowsAffected 的值是表中数据的数量 result.Error 返回是否有错误 返回如下结果
len:5err:<nil>
3. 使用Find()检索带条件
使用Where可以选择条件进行查询
db.Where("Price=?",20).Find(&products)
使用这个语句返回表中查询到的所有Price等于20的数据
3. 使用GORM库进行更新操作
1. 使用db.Model(&product).Update()改写已存在的数据
在Update()写入需要更新的数据的键值对,在Model中传入需要改动的结构体指针
var p []Product
db.First(&p,3)
fmt.Printf("p:%#v\n",p)
db.Model(&p).Update("Price",200)
fmt.Printf("p:%#v\n",p)
p:[]main.Product{main.Product{Model:gorm.Model{ID:0x3, CreatedAt:time.Date(2024, time.November, 25, 17, 55, 56, 769000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 17, 55, 56, 769000000, time.Local), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, Code:"B34", Price:0x32}}
p:[]main.Product{main.Product{Model:gorm.Model{ID:0x3, CreatedAt:time.Date(2024, time.November, 25, 17, 55, 56, 769000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 21, 12, 53, 457000000, time.Local), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, Code:"B34", Price:0xc8}}
可以看到Price已经被改动了,从原来的50被改成200了
2. 使用db.Model(&product).Updates() 更新多个字段
Updates() 方法可以同时更新多个字段。只要你在传入的结构体或 map 中指定了多个字段,它会一并更新
var p []Product
db.First(&p,5)
fmt.Printf("p:%#v\n",p)
db.Model(&p).Updates(Product{Code:"v78",Price: 700})
fmt.Printf("p:%#v\n",p)
我们可以看到一下输出信息,Code和Price已经被更新了
p:[]main.Product{main.Product{Model:gorm.Model{ID:0x5, CreatedAt:time.Date(2024, time.November, 25, 18, 7, 56, 364000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 18, 7, 56, 364000000, time.Local), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, Code:"D34", Price:0x32}}
p:[]main.Product{main.Product{Model:gorm.Model{ID:0x5, CreatedAt:time.Date(2024, time.November, 25, 18, 7, 56, 364000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 21, 23, 44, 72000000, time.Local), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, Code:"v78", Price:0x2bc}}
4. 使用GORM库进行删除操作
删除一条记录时,删除对象需要指定主键,否则会触发批量删除
1. 软删除
如果表中包含 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力!
当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录
2.根据主键删除
GORM 允许通过主键(可以是复合主键)和内联条件来删除对象,它可以使用数字,也可以使用字符串
db.Delete(&p)表明删除 p 对象在数据库中对应的记录,我这里选择主键为5的数据,gorm库会自动构建一条sql语句DELETE FROM products WHERE id = 5;来删除主键为5的记录
var p Product
db.First(&p,5)
fmt.Printf("p:%#v\n",p)
db.Delete(&p,5)
fmt.Printf("p:%#v\n",p)
p:main.Product{Model:gorm.Model{ID:0x5, CreatedAt:time.Date(2024, time.November, 25, 18, 7, 56, 364000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 21, 23, 44, 72000000, time.Local), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, Code:"v78", Price:0x2bc}
p:main.Product{Model:gorm.Model{ID:0x5, CreatedAt:time.Date(2024, time.November, 25, 18, 7, 56, 364000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 21, 23, 44, 72000000, time.Local),DeletedAt:gorm.DeletedAt{Time:time.Date(2024, time.November, 25, 21, 46, 22, 969000000, time.Local), Valid:true}}, Code:"v78", Price:0x2bc}
我们可以看到数据已经被软删除了,DeletedAt的值已经变成修改时间了
这时候再调用查询 db.First(&p,5),会显示record not found
3.查找被软删除的记录
可以使用Unscoped来查询到被软删除的记录
db.Unscoped().Where("id=5").Find(&users)
db.Unscoped().Where("id=5").Find(&products)
fmt.Printf("p:%#v\n",products)
我们可以看到被软删除的id为5的数据被查询到了
p:[]main.Product{main.Product{Model:gorm.Model{ID:0x5, CreatedAt:time.Date(2024, time.November, 25, 18, 7, 56, 364000000, time.Local), UpdatedAt:time.Date(2024, time.November, 25, 21, 23, 44, 72000000, time.Local), DeletedAt:gorm.DeletedAt{Time:time.Date(2024, time.November, 25, 21, 46, 22, 969000000, time.Local), Valid:true}}, Code:"v78", Price:0x2bc}}
4.永久删除记录
可以使用 Unscoped()来永久删除匹配的记录
下面的First语句会返回record not found 但是后面的永久删除语句生效了
var p Product
db.First(&p,5)
db.Unscoped().Where("id=5").Delete(&p)
使用查询函数
db.Unscoped().Where("id=5").Find(&p)
fmt.Printf("p:%#v\n",p)
返回以下信息,我们可以看到值全部为0,意味着我们查询不到这个id为5的数据了,它已经被我们永久删除了
[1.139ms] [rows:0] SELECT * FROM
productsWHEREproducts.id= 5 ANDproducts.deleted_atIS NULL ORDER BYproducts.idLIMIT 1 p:main.Product{Model:gorm.Model{ID:0x0, CreatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdatedAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletedAt:gorm.DeletedAt{Time:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Valid:false}}, Code:"", Price:0x0}
5.总结与思考
- GORM 提供了简洁的 API,将复杂的 SQL 操作封装为直观的函数调用,方便我们开发者使用,可以不用写冗余的SQL语句来操作数据库的数据。这种设计对不熟悉SQL语句的新手来说是非常友好,非常容易上手,提高开发效率,但隐藏了底层的 SQL 操作细节,如果想要深入了解数据库仍需要学习下SQL语句。
- GORM有非常丰富详细的文档,可供开发者参考,开发者可以根据文档快速上手,进行非常快捷便利的学习使用GORM库,降低了搜索使用方法的学习成本。 3.GORM 支持自动迁移功能(AutoMigrate),可以根据定义的结构体模型自动创建或更新数据库表。 这种特性让开发者不需要手动编写表结构的创建和修改语句,提高开发效率提供便利。 这种设计对快速开发项目和实现原型非常有帮助,但过度依赖可能导致开发者忽略对数据库结构的优化,可能会引发冗余字段或表设计不规范的问题。建议开发者在开发中使用GORM库的同时也不要忘了结合手动 SQL 脚本管理数据库结构,以确保更好的性能和稳定性