GO—web程序中的请求缓存设置

背景

假设用户数据存在数据库,现在需要一个函数,通过用户名称返回用户信息。
期望:在一次web请求中,不过调用多少次这个函数,只请求一次数据库。

基本信息

type User struct {Name stringAge  int
}func GetALLUserFromDB() []*User {return []*User{{Name: "Tom",Age:  18,},{Name: "Jerry",Age:  20,},}
}
重点

go的赋值都是值copy

实现
函数调用数据库
// GetUser 每次从数据库获取数据,根据名称返回user
func GetUser(_ context.Context, name string) *User {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}return allUserMap[name]
}func testGetUser(names []string) {for _, name := range names {fmt.Println(GetUser(context.Background(), name))}
}
  • 每次函数调用都会走到数据库
  • 不满足期望

在这里插入图片描述

使用一个map存储用户名和用户信息的关系
// GetUserWithParamCache 传入缓存map,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithParamCache(_ context.Context, name string, cache map[string]*User) *User {if cache == nil {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}cache = allUserMap}return cache[name]
}func testGetUserWithParamCache(names []string) {var cache map[string]*Userfor _, name := range names {fmt.Println(GetUserWithParamCache(context.Background(), name, cache))}
}
  • 参数传递是值copy,这里的形参不会影响实参。所以下次请求该函数的时候,cache总是为空
  • 注意,这里map的值copy是map的结构,其指向数据如果发生了变化,还是能影响实参的指向的数据的
    • 参考附录
  • 不满足期望

在这里插入图片描述

使用一个map存储用户名和用户信息的关系,map参数是指针类型
// GetUserWithParamCacheWithPointer 传入缓存map指针,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithParamCacheWithPointer(_ context.Context, name string, cache *map[string]*User) *User {if cache == nil || *cache == nil {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}*cache = allUserMap}return (*cache)[name]
}func testGetUserWithParamCacheWithPointer(names []string) {var cache map[string]*Userfor _, name := range names {fmt.Println(GetUserWithParamCacheWithPointer(context.Background(), name, &cache))}
}
  • 实参和形参都指向同一个map,该map变更时,实参指向的map也会变
  • 满足期望

在这里插入图片描述

使用context存储缓存
// GetUserWithCtxCache 从context中获取缓存map,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithCtxCache(ctx context.Context, name string) *User {cache, ok := ctx.Value("cache").(map[string]*User)if !ok {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}cache = allUserMapctx = context.WithValue(ctx, "cache", allUserMap)}return cache[name]
}func testGetUserWithCtxCache(names []string) {ctx := context.Background()for _, name := range names {fmt.Println(GetUserWithCtxCache(ctx, name))}
}
  • context也是值copy,实参不受影响
  • 不满足期望

在这里插入图片描述

context参数是指针,存储缓存
// GetUserWithCtxCacheWithPointer context为指针。从context中获取缓存map指针,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithCtxCacheWithPointer(ctx *context.Context, name string) *User {cache, ok := (*ctx).Value("cache").(map[string]*User)if !ok {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}cache = allUserMap*ctx = context.WithValue(*ctx, "cache", allUserMap)}return cache[name]
}func testGetUserWithCtxCacheWithPointer(names []string) {ctx := context.Background()for _, name := range names {fmt.Println(GetUserWithCtxCacheWithPointer(&ctx, name))}
}
  • 满足期望

在这里插入图片描述

附录
context设置value的情景
	t := context.Background().Value("cache")x,ok := t.(map[string]*User)fmt.Println(x,ok)ct := context.WithValue(context.Background(), "cache", nil)t = ct.Value("cache")x,ok = t.(map[string]*User)fmt.Println(x,ok)ct = context.WithValue(context.Background(), "cache", make(map[string]*User))t = ct.Value("cache")x,ok = t.(map[string]*User)fmt.Println(x,ok)ct = context.WithValue(context.Background(), "cache", map[string]*User{"Tom":&User{Name:"Tom",Age:18},"Jerry":&User{Name:"Jerry",Age:20}})t = ct.Value("cache")x,ok = t.(map[string]*User)fmt.Println(x,ok)

在这里插入图片描述

map作为参数
package mainfunc ChangeMap(t map[string]string) {t["a"] = "b"}func main() {x := map[string]string{"a": "a"}ChangeMap(x)println(x["a"])
}

在这里插入图片描述

完整代码
package mainimport ("context""fmt"
)type User struct {Name stringAge  int
}func GetALLUserFromDB() []*User {return []*User{{Name: "Tom",Age:  18,},{Name: "Jerry",Age:  20,},}
}// GetUser 每次从数据库获取数据,根据名称返回user
func GetUser(_ context.Context, name string) *User {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}return allUserMap[name]
}func testGetUser(names []string) {for _, name := range names {fmt.Println(GetUser(context.Background(), name))}
}// GetUserWithParamCache 传入缓存map,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithParamCache(_ context.Context, name string, cache map[string]*User) *User {if cache == nil {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}cache = allUserMap}return cache[name]
}func testGetUserWithParamCache(names []string) {var cache map[string]*Userfor _, name := range names {fmt.Println(GetUserWithParamCache(context.Background(), name, cache))}
}// GetUserWithParamCacheWithPointer 传入缓存map指针,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithParamCacheWithPointer(_ context.Context, name string, cache *map[string]*User) *User {if cache == nil || *cache == nil {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}*cache = allUserMap}return (*cache)[name]
}func testGetUserWithParamCacheWithPointer(names []string) {var cache map[string]*Userfor _, name := range names {fmt.Println(GetUserWithParamCacheWithPointer(context.Background(), name, &cache))}
}// GetUserWithCtxCache 从context中获取缓存map,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithCtxCache(ctx context.Context, name string) *User {cache, ok := ctx.Value("cache").(map[string]*User)if !ok {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}cache = allUserMapctx = context.WithValue(ctx, "cache", allUserMap)}return cache[name]
}func testGetUserWithCtxCache(names []string) {ctx := context.Background()for _, name := range names {fmt.Println(GetUserWithCtxCache(ctx, name))}
}// GetUserWithCtxCacheWithPointer context为指针。从context中获取缓存map指针,如果缓存map为空,从数据库获取数据,根据名称返回user
func GetUserWithCtxCacheWithPointer(ctx *context.Context, name string) *User {cache, ok := (*ctx).Value("cache").(map[string]*User)if !ok {fmt.Println("GetALLUserFromDB")allUser := GetALLUserFromDB()allUserMap := make(map[string]*User)for _, user := range allUser {allUserMap[user.Name] = user}cache = allUserMap*ctx = context.WithValue(*ctx, "cache", allUserMap)}return cache[name]
}func testGetUserWithCtxCacheWithPointer(names []string) {ctx := context.Background()for _, name := range names {fmt.Println(GetUserWithCtxCacheWithPointer(&ctx, name))}
}func main() {names := []string{"Tom", "Jerry", "Lucy"}fmt.Println("=====================================", "testGetUser")testGetUser(names)fmt.Println("=====================================", "testGetUserWithParamCache")testGetUserWithParamCache(names)fmt.Println("=====================================", "testGetUserWithParamCacheWithPointer")testGetUserWithParamCacheWithPointer(names)fmt.Println("=====================================", "testGetUserWithCtxCache")testGetUserWithCtxCache(names)fmt.Println("=====================================", "testGetUserWithCtxCacheWithPointer")testGetUserWithCtxCacheWithPointer(names)t := context.Background().Value("cache")x,ok := t.(map[string]*User)fmt.Println(x,ok)ct := context.WithValue(context.Background(), "cache", nil)t = ct.Value("cache")x,ok = t.(map[string]*User)fmt.Println(x,ok)ct = context.WithValue(context.Background(), "cache", make(map[string]*User))t = ct.Value("cache")x,ok = t.(map[string]*User)fmt.Println(x,ok)ct = context.WithValue(context.Background(), "cache", map[string]*User{"Tom":&User{Name:"Tom",Age:18},"Jerry":&User{Name:"Jerry",Age:20}})t = ct.Value("cache")x,ok = t.(map[string]*User)fmt.Println(x,ok)}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/698434.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react Effect副作用 - 避免滥用Effect

react Effect副作用 - 避免滥用Effect react Effect副作用基础概率什么是纯函数? 什么是副作用函数?纯函数副作用函数 什么时候使用Effect如何使用Effect 避免滥用Effect根据 props 或 state 来更新 state当 props 变化时重置所有 state将数据传递给父组件获取异步数据 react…

Android Activity因配置改变重建,ViewModel#onClear方法为什么不被调用?

1,问题 注意到切换语言或字体大小改变时,Activity会发生重建,但对应的ViewModel却不会被clear,甚至在重建的Activity,通过new ViewModelProvider(this).get(ViewModel.class)也是上一个Activity的实例,为什…

c++高级篇(一) —— 初识Linux下的进程控制

linux的信号 信号的概念 在Linux中,信号是一种用于进程间通信和处理异步事件的机制,用于进程之间相互传递消息和通知进程发生了事件,但是,它不能给进程传递任何数据。 信号产生的原因有很多种,在shell中&#xff0c…

C/C++ VScode: launch: program ...... dose not exist

VScode: launch: program … dose not exist 介绍 参考VS Code 配置 C/C 编程运行环境(保姆级教程)教程配置了VSCode。在配置launch.json适用多个.c 文件编译时,弹出下面错误。 原因和解决方法 是task.json 默认配置的问题。 默认的 cwd参…

Java数据类型:基本类型

Java是一种强类型语言,定义变量时,必须指定数据类型。 // 变量必须指定数据类型 private String username;初学者不免有个疑问:在实际编写代码的过程中,该如何选择数据类型呢? 回答这个问题之前,先来解决…

黑马点评项目总结及个人优化

怎么根据前端代码实现自己的后端业务,实现不同接口 查阅文档:如果有完善的接口文档,可以直接查阅文档来了解后端所有接口的业务逻辑和功能。 阅读后端代码:通过阅读后端代码,特别是控制器(Controller)层和服务(Service)层的代码,可以了解后端所有接口的具体实现逻辑。…

vscode主侧栏源代码管理(Source Control)不见了!!!

今天上班突然发现vscode中主侧栏中源代码管理(Source Control)不见了,项目又着急赶工,没时间找它,可真愁死我了。 以为这样代码没办法提交了??? 嘿嘿, 还好我用命令&a…

不限经验,专业,也能月薪2-3W,这个神仙副业今年太火了!

哈喽,大家好,我是醒醒团队电商花花。 一个月前,有朋友找我咨询视频号的问题,关于营业执照的问题,问我做视频号小店用什么营业执照,我就把视频号小店的营业执照问题给讲一下。 因为个体店执照在视频号上不…

PCB笔记(二十六):PCB检查

前言 首先检查元器件是否100% 放置 文章目录 1、打开DRC2、database check3、检查DRC4、检查多余的线5、其他需要注意的点a.检查差分线、等长线是否已调好b.注意检查晶振、电感等元件上/下方是否其他线经过(一般不允许线经过)c.打开place_bo…

【启明智显技术分享】SSD201/SSD202D核心板UI界面开发全攻略:LVGL使用指南

提示:作为Espressif(乐鑫科技)大中华区合作伙伴及sigmastar(厦门星宸)VAD合作伙伴,我们不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考。同时也用心整理了乐鑫及星宸…

浅谈电动汽车充电站的电气安全

1 引言 1月14日日上午10点左右,青岛市市北区辽宁路63号公交停车场内,一辆报废公交车突然起火,由于大风天气,大火很快引燃了停在旁边的几辆报废车。消防人员快速赶到,迅速控制住火势。11时30分,停车场内的…

AR项目的技术难点

AR项目的技术难点主要体现在以下几个方面,AR项目的技术难点体现在多个方面,需要从多个角度进行综合考虑。随着技术的进步和标准的完善,AR项目开发将会变得更加容易,AR技术也将得到更加广泛的应用。北京木奇移动技术有限公司&#…