GORM是什么
GORM(Go Object Relational Mapping)是一个用于 Go 语言的开源 ORM(对象关系映射)库。它提供了一种简单且强大的方式来将 Go 结构体与数据库表进行映射,从而实现对数据库的操作。
GORM 提供了丰富的功能,包括:
-
- 创建、更新、删除和查询数据库记录。
-
- 支持事务操作,确保数据的一致性。
-
- 支持多种关系类型,如一对一、一对多、多对多等。
-
- 自动映射结构体和数据库表,无需手动编写 SQL 语句。
-
- 支持链式查询和条件构建,方便灵活地组装查询条件。
-
- 提供丰富的回调函数,允许在执行数据库操作前后执行自定义逻辑。
-
- 支持数据库迁移和数据模型变更的管理。
-
- 可以与各种主流的关系型数据库进行集成,如 MySQL、PostgreSQL、SQLite 等。
使用 GORM,可以更加方便地操作数据库,减少了手写 SQL 语句的繁琐过程,提高了开发效率。同时,GORM 还提供了良好的扩展性和可定制性,可以根据实际需求进行个性化配置和扩展。
快速入门
安装
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
一般都会提示使用go install,go get失效,如果在配置go环境的时候没有在系统环境变量中添加GOPROXY,就去设置,变量值为https://goproxy.io,direct,
然后SET GO111MODULE=on
ps:我在Goland的Terminal中使用上述安装命令成功。
连接过程中的问题
gorm下载 go mod
进行连接以及创建数据
go mod
在连接数据库之前,要对我们的项目进行初始化。
1.在项目Terminal中初始化一个module,go mod init xxx(xxx是你自定义的名称)
2.项目目录中就会出现这个mod文件,接下来应该是下载modules到本地go mod download(但这一步也常常出现问题,我就选择直接在根目录下增加go.mod,然后将初始化的xxx.mod内容复制进去)
连接
初始化后就可以进行连接 使用
type Product struct {
...
}
db.AutoMigrate(&Product{})
进行建表
或者在mysql workbench进行创建相应表
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type Product struct {
ID uint
Code string
Price uint
}
func main() {
db, err := gorm.Open(
mysql.Open("username:psw@tcp(IP:port)/databasename?charset=utf8mb4&parseTime=True&loc=Local"),
&gorm.Config{})
if err != nil {
panic("failed to connect")
}
u1 := Product{1, "D23", 100}
db.Create(&u1)
}
type Product struct {}是使用gorm.Model结构体嵌套
需要注意的是
- username:数据库用户名
- psw:数据库连接密码
- IP:数据库的IP
- port:数据库端口
- databasename:数据库名称
以上需要根据自己的情况进行设定
上述代码在连接数据库的同时创建了第一条数据 其结果为
以及
可以看到我们创建的数据已经插入表中
创建多条数据:
func main() {
...
//1
pros := []*Product{{ID: 4}, {ID: 5}}
res := db.Create(pros)
//2
u2 := Product{6, "A35", 600}
u3 := Product{7, "B12", 100}
db.Create(&u2)
db.Create(&u3)
}
运行1后结果为:
运行2后的结果
1和2均为创建数据的代码,结果也可以从结果图中清楚看到
进行查询:
//查询第一条数据
func main() {
...
u := new(Product)
db.First(u)
fmt.Printf("%#v\n", u)
或者 //u :=&Product{}
//db.First(u)
//fmt.Printf("%#v\n",u)
}
结果是:
main.Product{ID:0x1, Code:"D23", Price:0x64}
可以看到有两个数据格式不对:GORM 框架默认使用 uint 类型的整数字段作为自增主键,并且在查询结果时,会将其转换为指向对应实体的指针类型。所以,无论你如何修改打印代码,GORM 都会以十六进制格式输出实体的 ID和Price 值。
查询其他与多条数据:
func main() {
...
pds := make([]*Product, 0)
result := db.Where("ID < n").Find(&pds)
fmt.Println(result.RowsAffected)//返回找到的记录数
}
这样我们可以查询到ID值小于n范围内的所有记录并进行打印到的记录数 如果想要打印结果,可以进行适当修改对fmt的调用。
修改数据
原本数据:
func main() {
...
//更新指定字段数据
//1
db.Model(&Product{ID: 5}).Updates(Product{Code: "R19", Price: 900})
//2
db.Model(&Product{ID: 4}).Select("Code").Updates(map[string]interface{}{"Code": "E90", "Price": 900})
}
结果是
可以注意到2语句只更新了Code的值,而Price值保持不变,这是因为在 GORM 中,使用 Select() 方法会限制更新操作只针对指定的字段,其他未指定的字段将不会被更新。这里Select指定的是Code,所以只会更新Code字段的数据
db.Model(&Product{ID:4}).Updates(map[string]interface{}{"Code":"E90","Price":900}) 舍弃Select可以做到更新多字段
如果是db.Model(&Product{9}).Where("Price<?",10).Update("Code", "E90")会报错too few values in struct literal of type Product
删除数据
func main() {
//物理删除
db.Delete(&Product{}, 2) //1
db.Delete(&Product{}, []int{4, 5}) //2
db.Where("ID LIKE ?","%7%").Delete(Product{}) //3
//软删除
//删除一条
u :=Product{ID:1}
db.Delete(&u)
//批量删除
db.Where("ID IN ?",[]int{6,7,8}).Delete(&Product{})
}
1.delete from Products where ID=2
2.delete from products where ID in (4,5),删除 ID 为 4 或 5 的记录
3.delete from products where id like "%7%",根据条件删除 ID 含有 7 的记录
物理删除和软删除
在 GORM 中,物理删除和软删除是两种不同的删除策略,它们具有以下区别:
-
- 物理删除:物理删除是直接从数据库中永久删除数据记录的操作。当您使用
db.Delete()方法执行物理删除时,相应的数据记录将被立即从数据库中删除,无法恢复。物理删除可以彻底清除不再需要的数据,但也可能导致数据的永久丢失。
- 物理删除:物理删除是直接从数据库中永久删除数据记录的操作。当您使用
-
- 软删除:软删除是一种将数据记录标记为已删除但保留在数据库中的操作。当您使用 GORM 提供的软删除功能时,实际上是更新了一个特定的字段来表示该记录已被删除。通常会使用一个名为
deleted_at的时间戳字段来标记删除的记录。软删除允许您在需要时轻松恢复或查看已删除的数据记录。
- 通过在gorm.Model模型中添加
DeletedAt字段,GORM 将自动处理软删除的操作。当您调用db.Delete()方法时,它会将记录的DeletedAt字段设置为当前时间,表示该记录已被删除。您可以使用db.Unscoped().Find()方法来查询包括软删除记录的所有数据,并可以使用db.Unscoped().Delete()方法永久删除软删除的记录。
- 软删除:软删除是一种将数据记录标记为已删除但保留在数据库中的操作。当您使用 GORM 提供的软删除功能时,实际上是更新了一个特定的字段来表示该记录已被删除。通常会使用一个名为