Database&SQL课程笔记与实战 | 青训营笔记

62 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第三篇笔记。

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 设计原理

image-20220518094318-5phdt1x.png

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)