这是我参与「第三届青训营 -后端场」笔记创作活动的第三篇笔记。
1 理解database/sql
理解database/sql包的目标是为程序提供一个统一的接口,并配合不同数据库的驱动包,来连接和访问不同的数据库
1.1 基本用法
使用driver+dsn初始化db连接
import (
"database/sql"
"driver/mysql"
)
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
rows, err := db.Query("{sql sequence}")
1.2 设计原理
2 GORM基础使用
GORM是全功能orm,ORM是一类采用元数据来描述对象与关系映射细节的框架,以解决面向对象与关系数据库不匹配的问题,通过orm中的映射文件,就能实现从数据库中读取对象和把对象持久化到数据库中。
2.2 基本用法 CRUD
// Create
db.Create(&Product{Code: "D42", Price: 100})
// Read
var product Product
db.First(&product, 1) // 根据整型主键查找
db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录
// Update - 将 product 的 price 更新为 200
db.Model(&product).Update("Price", 200)
// Update - 更新多个字段
db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
// Delete - 删除 product
db.Delete(&product, 1)
2.3 模型定义
Gorm使用约定优于于配置,如: 使用ID作为主键,使用结构体的蛇形命名作为表名,使用结构体字段名的蛇形命名作为数据表的列名等。
也可以自行配置,参考gorm.io/docs/conven… 。
3 GORM设计原理
相当于在database/sql包上加了一层
SQL是怎么生成的
每个SQL语句都是由很多子语句构成的,gorm的每个方法就对应一个子语句,再加上最后的执行类型语句,最终拼接编译成一个sql语句,拼接通过自定义builder,后续再依次扩展子句。
4 GORM实践
4.1 连接数据库
使用dsn配置数据库的参数,调用Gorm连接,并返回gorm.DB,以获取全局可用的db实例。
var db = getDB()
func getDB() *gorm.DB {
dsn := "root:password@tcp(127.0.0.1:3306)/tiktok?charset=utf8&parseTime=True&loc=Local"
database, err := gorm.Open(mysql.Open(dsn))
if err != nil {
fmt.Println(err)
}
return database
}
4.2 定义结构体
根据数据库表的设计和gorm的模型约定来定义结构体,以tokens表为例。 sql
CREATE TABLE `tokens` (
`token_id` int NOT NULL AUTO_INCREMENT,
`user_token` varchar(45) NOT NULL,
`user_id` int NOT NULL,
`expire_time` timestamp NOT NULL,
PRIMARY KEY (`token_id`),
KEY `userToken&expireTime` (`user_token`,`expire_time`)
) ENGINE=InnoDB AUTO_INCREMENT=68 DEFAULT CHARSET=utf8
对应的结构体
type Token struct {
TokenId int `gorm:"primaryKey"`
UserToken string
UserId int
ExpireTime time.Time
}
4.3 增删查改
创建失效时间为生成时间往后10分钟的token,其中主键为自增
var tokenValidDuration, _ = time.ParseDuration("10m")
expireTime := time.Now().Add(tokenValidDuration) // token的失效时间是现在的时间后延十分钟
var tokenInfo = Token{UserToken: userToken, UserId: userId, ExpireTime: expireTime}
result := db.Create(&tokenInfo)
删除token
//删除指定id的记录
result := db.Delete(&Token{}, tokenId)
//删除所有记录
result := db.Where("1 = 1").Delete(&Token{})
查询失效时间在当前时间之后的token,即还没过期的token
now := time.Now()
result := db.Where(&Token{UserToken: userToken}).Where("expire_time > ?", now).Limit(1).Find(&tokenInfo)
更新token的失效时间
var tokenValidDuration, _ = time.ParseDuration("10m")
tokenInfo.ExpireTime = time.Now().Add(tokenValidDuration) // token的失效时间是现在的时间后延十分钟
result := db.Save(&tokenInfo)