**Gin **框架入门实战系列教程
主讲教师:(大地)
在线文档:https://www.itying.com/gin
我的专栏:https://www.itying.com/category-79-b0.html
十三、**Gin **中的 Session
13.1 、Session 简单介绍
session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session 保存在服务器上。
13.2 、Session 的工作流程
:::info
当客户端浏览器第一次访问服务器并发送请求时,服务器端会创建一个 session 对象,生成 一个类似于 key,value 的键值对,然后将 value 保存到服务器 将 key(cookie)返回到浏览器(客 户)端。浏览器下次访问时会携带 key(cookie) ,找到对应的 session(value)。
:::
13.3 、Gin 中使用 Session
:::info
Gin 官方没有给我们提供 Session 相关的文档,这个时候我们可以使用第三方的 Session 中间 件来实现
:::
https://github.com/gin-contrib/sessions
:::info
gin-contrib/sessions 中间件支持的存储引擎:
• cookie
• memstore
• redis
• memcached
• mongodb
:::
13.4 、基于 Cookie 存储 Session
1 、安装 session 包
go get github.com/gin-contrib/sessions
2 、基本的 session 用法
package main
import (
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 创建基于 cookie 的存储引擎,secret11111 参数是用于加密的密钥 store := cookie.NewStore([]byte("secret11111"))
// 设置 session 中间件,参数 mysession ,指的是 session 的名字,也是 cookie 的名字
// store 是前面创建的存储引擎,我们可以替换成其他存储引擎
r.Use(sessions.Sessions("mysession", store))
r.GET("/", func(c *gin.Context) {
//初始化 session 对象
session := sessions.Default(c)
//设置过期时间
session.Options(sessions.Options{
MaxAge: 3600 * 6, // 6hrs
})
//设置 Session
session.Set("username", "张三")
session.Save()
c.JSON(200, gin.H{"msg" : session.Get("username")})
})
r.GET("/user", func(c *gin.Context) {
// 初始化 session 对象
session := sessions.Default(c)
// 通过 session.Get 读取 session 值
username := session.Get("username")
c.JSON(200, gin.H{"username" : username})
})
r.Run(" :8000")
}
13.5 、基于 Redis 存储 Session
:::info
如果我们想将 session 数据保存到 redis 中,只要将 session 的存储引擎改成 redis 即可。
使用 redis 作为存储引擎的例子:
首先安装 redis 存储引擎的包
:::
go get github.com/gin-contrib/sessions/redis
例子:
package main
import (
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/redis"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 初始化基于 redis 的存储引擎
// 参数说明:
// 第 1 个参数 - redis 最大的空闲连接数
// 第 2 个参数 - 数通信协议tcp 或者 udp
// 第 3 个参数 - redis 地址, 格式,host:port
// 第 4 个参数 - redis 密码
// 第 5 个参数 - session 加密密钥
store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("secret"))
r.Use(sessions.Sessions("mysession", store))
r.GET("/", func(c *gin.Context) {
session := sessions.Default(c)
session.Set("username", "李四")
session.Save()
c.JSON(200, gin.H{"username" : session.Get("username")})
})
r.GET("/user", func(c *gin.Context) {
// 初始化 session 对象
session := sessions.Default(c)
// 通过 session.Get 读取 session 值
username := session.Get("username")
c.JSON(200, gin.H{"username" : username})
})
r.Run(" :8000")
}
十四、**Gin **中使用 **GORM **操作 **mysql **数据库
14.1 、GORM 简单介绍
:::info
GORM 是 Golang 的一个 orm 框架。简单说,ORM 就是通过实例对象的语法,完成关系型 数据库的操作的技术,是"对象-关系映射"(Object/ Relational Mapping) 的缩写。使用 ORM 框架可以让我们更方便的操作数据库。
**GORM **官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server
:::
:::info
Gorm 特性
• 全功能 ORM
• 关联 (Has One ,Has Many ,Belongs To ,Many To Many ,多态,单表继承)
• Create ,Save ,Update ,Delete ,Find 中钩子方法
• 支持 Preload 、Joins 的预加载
• 事务,嵌套事务,Save Point ,Rollback To Saved Point
• Context 、预编译模式、DryRun 模式
• 批量插入,FindInBatches ,Find/Create with Map ,使用 SQL 表达式、Context Valuer 进 行 CRUD
• SQL 构建器,Upsert ,数据库锁,Optimizer/ Index/Comment Hint ,命名参数,子查询
• 复合主键,索引,约束
• Auto Migration
• 自定义 Logger
• 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus …
• 每个特性都经过了测试的重重考验
• 开发者友好
:::
官方文档:https://gorm.io/zh_CN/docs/index.html
14.2 、Gin 中使用 GORM
1 、安装
如果使用 go mod 管理项目的话可以忽略此步骤
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
2 、Gin 中使用 Gorm 连接数据库
在 models 下面新建 core.go ,建立数据库链接
package models
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
var err error
func init() {
dsn := "root:123456@tcp(192.168.0.6:3306)/gin?charset=utf8mb4&parseTime=True&loc= L ocal"
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println(err)
}
}
3 、定义操作数据库的模型
:::info
Gorm 官方给我们提供了详细的:
https://gorm.io/zh_CN/docs/models.html
虽然在 gorm 中可以指定字段的类型以及自动生成数据表,但是在实际的项目开发中,我们 是先设计数据库表,然后去实现编码的。
在实际项目中定义数据库模型注意以下几点:
1 、结构体的名称必须首字母大写 ,并和数据库表名称对应。例如:表名称为 user 结构体 名称定义成 User ,表名称为 article_cate 结构体名称定义成 ArticleCate
2 、结构体中的字段名称首字母必须大写,并和数据库表中的字段一一对应。例如:下面结 构体中的 Id 和数据库中的 id 对应, Username 和数据库中的 username 对应,Age 和数据库中 的 age 对应,Email 和数据库中的 email 对应,AddTime 和数据库中的 add_time 字段对应
3 、默认情况表名是结构体名称的复数形式。如果我们的结构体名称定义成 User ,表示这个 模型默认操作的是 users 表。
4 、我们可以使用结构体中的自定义方法 TableName 改变结构体的默认表名称,如下:
:::
func (User) TableName() string {
return "user"
}
表示把 User 结构体默认操作的表改为 user 表
定义 **user **模型:
package models
type User struct { // 默认表名是 `users`
Id int
Username string
Age int
Email string
AddTime int
}
func (User) TableName() string {
return "user"
}
关于更多模型定义的方法参考:https://gorm.io/zh_CN/docs/conventions.html
gorm.Model
GORM 定义一个 gorm.Model 结构体,其包括字段 ID 、CreatedAt 、UpdatedAt 、DeletedAt
// gorm.Model 的定义
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
14.3 、Gin GORM CURD
找到要操作数据库表的控制器,然后引入 models 模块
1 、增加
增加成功后会返回刚才增加的记录
func (con UserController) Add(c *gin.Context) {
user := models.User{
Username: "itying.com",
Age: 18,
Email: "itying@qq.com",
AddTime: int(time.Now().Unix()),
}
result := models.DB.Create(&user) // 通过数据的指针来创建
if result.RowsAffected > 1 {
fmt.Print(user.Id)
}
fmt.Println(result.RowsAffected)
fmt.Println(user.Id)
c.String(http.StatusOK, "add 成功")
}
更多增加语句:https://gorm.io/zh_CN/docs/create.html
2 、查找
查找全部
func (con UserController) Index(c *gin.Context) {
user := []models.User{}
models.DB.Find(&user)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : user,
})
}
指定条件查找
func (con UserController) Index(c *gin.Context) {
user := []models.User{}
models.DB.Where("username=?", "王五").Find(&user)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : user,
})
}
更多查询语句:https://gorm.io/zh_CN/docs/query.html
3 、修改
func (con UserController) Edit(c *gin.Context) {
user := models.User{Id: 7}
models.DB.Find(&user)
user.Username = "gin gorm"
user.Age = 1
models.DB.Save(&user)
c.String(http.StatusOK, "Edit")
}
更多修改的方法参考:https://gorm.io/zh_CN/docs/update.html
4 、删除
func (con UserController) Delete(c *gin.Context) {
user := models.User{Id: 8}
models.DB.Delete(&user)
c.String(http.StatusOK, "Delete")
}
更多删除的方法参考:https://gorm.io/zh_CN/docs/delete.html
5 、批量删除
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
// DELETE from emails where email LIKE "%jinzhu%";
db.Delete(Email{}, "email LIKE ?", "%jinzhu%")
// DELETE from emails where email LIKE "%jinzhu%";
func (con UserController) DeleteAll(c *gin.Context) {
user := models.User{}
models.DB.Where("id>9").Delete(&user)
c.String(http.StatusOK, "DeleteAll")
}
更多删除的方法参考:https://gorm.io/zh_CN/docs/delete.html
14.4 、Gin GORM 查询语句详解
https://gorm.io/zh_CN/docs/query.html
1 、Where
:::tips
<
>
<=
>=
!=
IS NOT NULL
IS NULL
BETWEEN AND
NOT BETWEEN AND
IN
OR
AND
NOT
LIKE
:::
nav := []models.Nav{}
models.DB.Where("id<3").Find(&nav)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : nav,
})
var n = 5
nav := []models.Nav{}
models.DB.Where("id>?", n).Find(&nav)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : nav,
})
var n1 = 3
var n2 = 9
nav := []models.Nav{}
models.DB.Where("id > ? AND id < ?", n1, n2).Find(&nav)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : nav,
})
nav := []models.Nav{}
models.DB.Where("id in (?)", []int{3, 5, 6}).Find(&nav)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : nav,
})
nav := []models.Nav{}
models.DB.Where("title like ?", "%会%").Find(&nav)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : nav,
})
nav := []models.Nav{}
models.DB.Where("id between ? and ?", 3, 6).Find(&nav)
c.JSON(http.StatusOK, gin.H{
"success" : true,
"result" : nav,
})
2 、Or 条件
nav := []models.Nav{}
models.DB.Where("id=? OR id=?", 2, 3).Find(&nav)
nav := []models.Nav{}
models.DB.Where("id=?", 2).Or("id=?", 3).Or("id=4").Find(&nav)
3 、选择字段查询
nav := []models.Nav{}
models.DB.Select("id, title,url").Find(&nav)
4 、排序 Limit 、Offset
nav := []models.Nav{}
models.DB.Where("id>2").Order("id Asc").Find(&nav)
nav := []models.Nav{}
models.DB.Where("id>2").Order("sort Desc").Order("id Asc").Find(&nav)
nav := []models.Nav{}
odels.DB.Where("id>1").Limit(2).Find(&nav)
跳过 2 条查询 2 条
nav := []models.Nav{}
models.DB.Where("id>1").Offset(2).Limit(2).Find(&nav)
5 、获取总数
nav := []models.Nav{}
var num int
models.DB.Where("id > ?", 2).Find(&nav).Count(&num)
6 、Distinct
从模型中选择不相同的值
nav := []models.Nav{}
models.DB.Distinct("title").Order("id desc").Find(&nav)
c.JSON(200, gin.H{
" "
nav : nav,
})
SELECT DISTINCT `title` FROM `nav` ORDER BY id desc
7 、Scan
type Result struct {
Name string
Age int
}
var result Result
db.Table("users").Select("name", "age").Where("name = ?", "Antonio").Scan(&result)
// 原生 SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)
var result []models.User
models.DB.Raw("SELECT * FROM user").Scan(&result)
fmt.Println(result)
8 、Join (先了解 后面课程会讲关联查询)
type result struct {
Name string
Email string
}
db. Model(&User{}).Select("users. name, emails.email").Joins("left join emails on emails.user_i d = users.id").Scan(&result{})
SELECT users.name, emails.email FROM `users` left join emails on emails.user_id = users.i d
14.5 、Gin GORM 查看执行的 sql
func init() {
dsn :=
"root:123456@tcp(192.168.0.6:3306)/gin?charset=utf8mb4&parseTime=True&loc=Local"
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
QueryFields: true,
})
// DB.Debug()
if err != nil {
fmt.Println(err)
}
}
十五、原生 **SQL **和 **SQL **生成器
更多使用方法参考:
https://gorm.io/zh_CN/docs/sql_builder.html
1 、使用原生 sql 删除 user 表中的一条数据
| result := models.DB.Exec(“delete from user where id=?”, 3)
fmt.Println(result.RowsAffected) |
---|
2 、使用原生 sql 修改 user 表中的一条数据
result := models.DB.Exec(“update user set username=? where id=2”, " 哈哈") fmt.Println(result.RowsAffected) |
---|
3 、查询 uid=2 的数据
| var result models.User
models.DB.Raw(“SELECT * FROM user WHERE id = ?”, 2).Scan(&result)
fmt.Println(result) |
---|
4 、查询 User表中所有的数据
| var result []models.User
models.DB.Raw(“SELECT * FROM user”).Scan(&result)
fmt.Println(result) |
---|
5 、统计 user 表的数量
| var count int
row := models.DB.Raw(“SELECT count(1) FROM user”).Row(&count )
row.Scan(&count) |
---|