这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。基于上课所讲内容,查阅官方文档,进行了简单的gorm的学习。
官方文档:(GORM 指南)
什么是orm框架
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。那么,到底如何实现持久化呢?一种简单的方案是采用硬编码方式,为每一种可能的数据库访问操作提供单独的方法。
这种方案存在以下不足:
1.持久化层缺乏弹性。一旦出现业务需求的变更,就必须修改持久化层的接口
2.持久化层同时与域模型与关系数据库模型绑定,不管域模型还是关系数据库模型发生变化,毒药修改持久化曾的相关程序代码,增加了软件的维护难度。
ORM提供了实现持久化层的另一种模式,它采用映射元数据来描述对象关系的映射,使得ORM中间件能在任何一个应用的业务逻辑层和数据库层之间充当桥梁。Java典型的ORM中间件有:Hibernate,ibatis,speedframework。
ORM的方法论基于三个核心原则:
· 简单:以最基本的形式建模数据。
· 传达性:数据库结构被任何人都能理解的语言文档化。
· 精确性:基于数据模型创建正确标准化了的结构。
数据库链接
主要说明mysql的链接 部分配置参数的说明: DNS:链接数据库的基本参数,包含用户名,数据库名称,密码,链接地址。根据数据库自行修改
DefaultStringSize: string 类型字段的默认长度 uft8为255 utf8mb4为191
SkipInitializeWithVersion: 根据当前 MySQL 版本自动配置
DisableForeignKeyConstraintWhenMigrating: 使用逻辑外键,不使用物理外键以增加性能
TablePrefix: "t_",所有的表前增加前缀"t_"
SingularTable: false 建表采用复数模式
db, _ := gorm.Open(mysql.New(mysql.Config{
DSN: "username:passwword@tcp(127.0.0.1:3306)/databasename?charset=utf8mb4&parseTime=True&loc=Local",
DefaultStringSize: 191,
SkipInitializeWithVersion: true, // 根据当前 MySQL 版本自动配置
}), &gorm.Config{
SkipDefaultTransaction:false,
DisableForeignKeyConstraintWhenMigrating: true,
NamingStrategy: schema.NamingStrategy{
TablePrefix: "t_",
SingularTable: false, this option enabled
},
})
连接池的配置
SetMaxIdleConns 用于设置连接池中空闲连接的最大数量。
SetMaxOpenConns 设置打开数据库连接的最大数量。
SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
模型与建表
model
其中user为user模型,对应user表,userinfo是一个数据容器,可以用来搜索相应字段。
gorm.Model:
GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
type User struct {
gorm.Model
Name string
Age uint8 `gorm:"default:18"`
}
type UserInfo struct {
Name string
Age uint8
}
建表
AutoMigrate 会创建表、缺失的外键、约束、列和索引。 如果大小、精度、是否为空可以更改,则 AutoMigrate 会改变列的类型。 出于保护您数据的目的,它不会删除未使用的列
db.AutoMigrate(&User{})
数据的增删查改
增
创建
user := User{Name: "zzz", Age: 20}
result := db.Create(&user) // 通过数据的指针来创建
user.ID // 返回插入数据的主键
result.Error // 返回 error
result.RowsAffected // 返回插入记录的条数
批量创建
要有效地插入大量记录,请将一个 slice 传递给 Create 方法。 GORM 将生成单独一条SQL语句来插入所有数据,并回填主键的值,钩子方法也会被调用。
var users = []User{
{Name: "1"},
{Name: "2"},
{Name: "3"}
} db.Create(&users)
除了通过结构体,还可以通过map创建
db.Model(&User{}).Create(map[string]interface{}{ "Name": "zzz", "Age": 20, })
查
GORM 提供了 First、Take、Last 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误
// 获取第一条记录(主键升序)
db.First(&user)
db.Limit(1).Find(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;
如果主键是数字类型,您可以使用 内联条件 来检索对象。 传入字符串参数时,需要特别注意 SQL 注入问题。
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;
db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;
db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);
条件查询
查询名字为zzz的第一个用户
查询年龄为20的用户
db.Where("name = ?", "zzz").First(&user)
db.Where("Age <> ?", "20").Find(&users)
将数据保存到容器,保留干净字段。
u:=UserInfo{}
DB.Model(&User{}).Select("name").First(&u)
//若想保留干净的所需要的字段,使用一个新的结构体作为容器接受,表模型通过Model()方法传递
更多查询见官方文档gorm.io/zh_CN/docs/…
改
save 会保存所有的字段,即使字段是零值,先查后改
update 更新单个列
updates 更新多列,使用结构体不会更新零值,使用map会更新零值
先查后改,将find换成如上方法。
db.Model(&User{}).Where("name LIKE ?", "%z%").Update("name", "hello")
user:=User{}
DB.First(&user)
DB.Model(&user).Updates(User{Name: "xxx", Age: 21})
users:=[]User{}
db.Where(&User{Name: "zzz"}).Find(&users)
for k,_:=range users{
users[k].Name="hello"
}
db.Save(&users)
删
普通删除
db.Delete(&user)
钩子
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
//对于删除操作,GORM 支持 BeforeDelete、AfterDelete Hook,在删除记录时会调用这些方法,查看 Hook 获取详情
if u.Name == "zzz" {
fmt.Println("删除失败")
return errors.New("user not allowed to delete")
}
return
}
软删除
如果您的模型包含了一个 gorm.deletedat 字段(gorm.Model 已经包含了该字段),它将自动获得软删除的能力!
拥有软删除能力的模型调用 Delete 时,记录不会从数据库中被真正删除。但 GORM 会将 DeletedAt 置为当前时间, 并且你不能再通过普通的查询方法找到该记录。
查找被软删除的记录
可以使用 Unscoped 找到被软删除的记录
db.Unscoped().Where("age = 20").Find(&users) // SELECT * FROM users WHERE age = 20;
永久删除
可以使用 Unscoped 永久删除匹配的记录
db.Unscoped().Delete(&order) // DELETE FROM orders WHERE id=10;