这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记,如有错误还请指正。 【有船启航】
理解database/sql
1. 基本用法
- import driver 实现,使用driver + DSN初始化DB 连接
- 执行一条SQL,通过rows取回返回的数据处理完毕,需要释放链接
- 数据、错误处理
2. 设计原理
-
上层应用操作接口
-
连接池管理:配置、取状态
-
操作过程:
- 设置最大重试次数,优先使用空闲连接,再考虑新建连接,如果之前的空闲连接都出错,在最后一次重试时设计为 新建连接
- defer连接放回连接池
- 连接实现操作、错误处理
- 只要有一次没返回错误就break
-
数据库连接接口:
DB连接类型:Conn(直接链接)、Stmt(预编译)、Tx(事务)
-
数据库操作接口
多批数据解析,减少对象copy
3. 基础概念(略)
2. GORM使用简介
1. 基本用法-CRUD
1. 操作数据库
db.AutoMigrate(&Product0)
db.Migrator().CreateTable(&Product)
//https://gorm.io/docs/migration.html
//版本管理- https://github.com/go-gormigrate/gormigrate
2.创建
result :=db.Create(&user) //pass pointer of data to Create
user.ID //派回主键last insert id
result.Error //返回error
result.RowsAffected //返回影响的行数
3.批量创建
db.Create(&users)
db . CreateInBatches(users,100)
for -, user := range users {
user.ID// 1,2,3
}
4.读取
db.First(&product,1) //查询id为1的product
db.First(&product,"code = ?","L1212")//查询code为L1212的product
result := db.Find(&users,int{1,2,3})
result.RowsAffected //返回找到的记录数
errors.Is(result.Error,gorm.ErrRecordNotFound) // First,Last,Take查不到数据
5.更新
db.Model(&product).Update( "Price",2000)
db.Model(&product).UpdateColumn( "Price",2000)
//更新多个字段
db.Model(&product).Updates(Product{Price: 2000,Code: "L1212"3)
db.Model(&product).Updates(map[string]interface{"Price": 2000, "Code": "L1212"}})
//批量更新
db.Model(&Product0).Where("price ?", 2000).Updates(map[string]interface{}{"Price" : 2000})
6.删除
db.Delete(&product)
2. Model定义与惯例约定
约定优于配置
- 表名为struct name的snake_cases复数格式
- 字段名为field name的snake_case单数格式
- ID/ld字段为主键,如果为数字,则为自增主键
- CreatedAt字段,创建时,保存当前时间
- UpdatedAt字段,创建、更新时,保存当前时间
- gorm.DeletedAt字段,默认开启soft delete模式
4. 关联操作
介绍
User拥有一个 Account (has one),拥有多个 Pets (has many),多个Toys(多态has many),属于某 Company (belongs to)属于某 Manager(单表 belongs to)管理Team(单表 has many),会多种 Languages (many to many)拥有很多 Friends(单表 many to many),并且他的Pet也有一个玩具 Toy(多态has one)。
CRUD
//保存用户及其关联(Upsert)
db. Save(&User{
Name :"jinzhu",
Languages:[]Language{{Name: "zh-CN"},{Name: "en-US"}},
}
//关联模式
langAssociation := db.Model(&user).Association("Languages")
//查询关联
langAssociation.Find(&languages)
//将汉语,英语语添加到用户掌握的语言中
langAssociation. AppendCLanguage{languageZH,languageEN})
//把用户掌握的语言替换为汉语,德语
langAssociation.Replace(Language{languageZH,languageDE})
//删除用户掌握的两个语言
langAssociation.Delete(languageZH,languageEN)
//删除用户所有掌握的语言
langAssociation.Clear()
//返回用户所掌握的语言的数量
langAssociation.Count()
//批量模式Append,Replace
var users=User{user1,user2,user3}
langAssociation := db.Model(&users).Association("Languages")
//批量模式 Append,Replace,参数需要与源数据长度相同
//例如:我们有 3个user:将userA 添加到user1 的Team.
//将userB 添加到user2的 Team, 将userA、userBp userC添加到user3的Team
db.Model(&users).Association("Team").Append(&userA,&userB,&[]User{userA,userB,userC})
Preload/Joins预加载
type User struct {
Orders []Order
Profile Profile
}
//查询用户的时候并找出其订单,个人信息(1+1条SQL)
db.Preload("Orders").Preload("Profile").Find(&users)
//SELECT *FROM users;
//SELECT * FROM orders WHERE user_id IN (1,2,3,4);//一对多
//SELECT * FROM profiles WHERE user_id IN (1,2,3,4);//一对一
//使用Join SQL 加载(单条JOINSQL)
db.Joins("Company").Joins("Manager").First(&user, 1)
db.Joins("Company",DB.Where(&Company{Alive: true})).Find(&users)
//预加载全部关联(只加载一级关联)
db.Preload(clause.Associations).Find(&users)
//多级预加载
db.Preload("Orders.OrderItems.Product").Find(&users)
//多级预加载+预加载全部一级关联
db.Preload("Orders.OrderItems.Product").Preload(clause.Associations).Find(&users)
//查询用户的时候找出其未取消的订单
db.Preload("Orders", "state NOT IN (?)","cancelled").Find&users)
db.Preload("Orders", "state = ?", "paid").Preload("orders.OrderItems").Find(&users)
db.Preload("Orders", func(db *gorm.DB) *gorm.DB{
return db.0rder("orders.amount DESC")
}).Find(&users)
联级删除
//方法1:使用数据库约束自动副除
type User struct {
ID uint
Name string
Account Account `gorm:"constraint:0nUpdate:CASCADE,OnDelete:CASCADE;"`
CreditCards []CreditCard `garm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
Orders []Oorder `gorm: "constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}
//需要使用 GORM Migrate 数据库迁移数据库外,才行
db.AutoMigrate(&User)
//如果未启用软删除,在删除User时会自动删除其依赖
db.Delete(&User)
//方法2:使用Select实现级联删际,不依赖数据库约束及软删除
//删除user时,也删除user 的account
db.Selectc("Account").Delete(&user)
//删除user 时,也聊除user的Orders、CreditCards记录
db.Selectc("Orders","CreditCards").Delete(&user)
//删除user时,也删除 user的Orders、Creditards记录,也删除订单的BillingAddress
db. Select("Orders","Orders.BillingAddress","CreditCards").Delete(&user)
//删除user时,也删除用户及其依赖的所有has one/many、many2many记录
db . Select(clause.Associations).Delete(&user)
3. GORM设计原理
1. 扩展子句
2. 选择子句
3. 插件系统
Finisher Method->决定Statement类型->执行Callbacks->生成 SQL并执行
Callbacks模式: - Create - Query - Update - Delete - Row - Raw
- 通过配置实现多数据库、读写分离
- 全局模式:将所有DB操作(缓存不含参数部分)预编译,再根据新的参数去执行,提高执行速度
- 会话模式:将后续会话DB操作预编译,再根据新的参数去执行,提高执行速度
4. 连接池
- 提高运行速度的方式: interpolateParams=true,默认为false,会执行前预编译SQL,然后调用预编译SQL,但是调用后就会删除预编译,并不缓存,所以运行速度会降低。