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

背景

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

基本信息

type User struct {
	Name string
	Age  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]*User
	for _, 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]*User
	for _, 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 = allUserMap
		ctx = 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 main

func ChangeMap(t map[string]string) {
	t["a"] = "b"

}

func main() {
	x := map[string]string{"a": "a"}
	ChangeMap(x)
	println(x["a"])
}

在这里插入图片描述

完整代码
package main

import (
	"context"
	"fmt"
)

type User struct {
	Name string
	Age  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]*User
	for _, 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]*User
	for _, 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 = allUserMap
		ctx = 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)

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器3389端口,服务器3389端口风险提示的应对措施

3389端口是Windows操作系统中远程桌面协议(RDP)的默认端口。一旦该端口被恶意攻击者利用,可能会导致未经授权的远程访问和数据泄露等严重安全问题。 针对此风险,强烈建议您采取以下措施: 1. 修改默认端口:…

苹果手机系统恢复工具:轻松解决iPhone各类系统问题!

随着苹果手机的iOS系统不断升级,越来越多的系统问题不断出现,如卡在恢复模式、系统崩溃白苹果、应用无响应、等,这些问题不仅影响用户体验,还可能导致手机无法正常使用。 遇到系统问题,一般我们可以先尝试使用强制重启…

【原创】springboot+mysql校园宿舍报修管理系统设计与实现

个人主页:程序猿小小杨 个人简介:从事开发多年,Java、Php、Python、前端开发均有涉猎 博客内容:Java项目实战、项目演示、技术分享 文末有作者名片,希望和大家一起共同进步,你只管努力,剩下的交…

景源畅信:小白如何做抖音电商怎么样?

在数字浪潮中崛起的抖音电商,以其独特的平台优势吸引了众多创业者的目光。特别是对于初入电商领域的“小白”来说,如何在这个全新的领域站稳脚跟,成为他们迫切需要解答的问题。接下来,我们将深入探讨小白如何在抖音电商中开辟属于…

免费思维13招之十:增值型思维

免费思维13招之十:增值型思维 免费思维的另一大战略思维——增值型思维。 为了提高客户的粘性而促进重复性消费,我们必须对客户进行免费的增值型服务。 大家不要把增值型思维与赠品型思维混淆,增值型思维重心在于提高与消费者的粘性而促进重复消费,重心在后端。而赠品型思…

Spring Cloud Alibaba 分布式配置中心(9)

项目的源码地址 Spring Cloud Alibaba 工程搭建(1) Spring Cloud Alibaba 工程搭建连接数据库(2) Spring Cloud Alibaba 集成 nacos 以及整合 Ribbon 与 Feign 实现负载调用(3) Spring Cloud Alibaba Ribbo…

【简单介绍下Milvus】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…

vue3专栏项目 -- 四、前后端结合(下)

一、async 和 await 1、使用async 和 await 改造异步请求 在接触后端API以后就遇到了越来越多的异步请求,现在我们就使用async 和 await 改造异步请求。 async function是把返回内容包裹成个Promise返回Promise await 它在async function里面才起作用&#xff0…

互联网轻量级框架整合之SpringIoC概念详解

在之前的几篇文字中说道容器的概念,实际上Spring也是基于容器的理念,之所以如此成功并不是因为很先进的技术,而是因为理念,其中核心便是IoC(控制反转),AOP(面向切面编程),其中IoC是Spring的基础&#xff0c…

腐烂的橘子 - (LeetCode)

一、概述 994. 腐烂的橘子 - 力扣(LeetCode),今天刷到这道题,开始按照自己实现的思路写了一次,通过了调试,但是提交的时候,来了一个大的数据,就没有通过测试,百思不得其…

commvault学习(7):恢复oracle

在实际生产环境中,oracle的恢复方式大部分是异机恢复。 环境: 备份机:windows server2008,ip:192.168.20.56 恢复目标机:windows server2008,ip:192.168.20.55 CS、MA&#xff1…

进程和计划任务管理

查看系统进程信息 静态查看系统进程信息之ps命令 (每五秒刷新一次数据) 方法一:ps aux //显示所有进程 a:显示现行终端下的所有进程,包括其它用户的进程。u:显示进程的归属用户及内存的使用情况。x…

今天开发了一款软件,我竟然只用敲了一个字母(文末揭晓)

软件课题:Python实现打印100内数学试题软件及开发过程 一、需求管理: 1.实现语言:Python 2.打印纸张:A4 3.铺满整张纸 4.打包成exe 先看效果: 1. 2.电脑打印预览 3.打印到A4纸效果(晚上拍的&#x…

Java入门基础学习笔记22——程序流程控制

程序流程控制:控制程序的执行顺序。 程序有哪些执行顺序? 顺序、分支和循环。 分支结构: if、switch 循环: for、while、do-while 顺序结构是程序中最简单最基本的流程控制,没有特定的语法结构,按照代码…

​​​【收录 Hello 算法】第 6 章 哈希表

目录 第 6 章 哈希表 本章内容 第 6 章 哈希表 Abstract 在计算机世界中,哈希表如同一位聪慧的图书管理员。 他知道如何计算索书号,从而可以快速找到目标图书。 本章内容 6.1 哈希表6.2 哈希冲突6.3 哈希算法6.4 小结

文本分类的深度注意图扩散网络 笔记

1 Title Deep Attention Diffusion Graph Neural Networks for Text Classification(Yonghao Liu、Renchu Guan、Fausto Giunchiglia、Yanchun Liang、Xiaoyue Feng)【EMnlp 2021】 2 Conclusion Text classification is a fundamental task with broad…

20240513,常用算法(查找,排序,拷贝替换)

做着一些和考试无关的事情 常用查找算法——续 FIND_IF find_if //按条件查找元素&#xff0c;返回迭代器POS / END()find_if(beg,end,_Fred) _Fred函数或谓词&#xff08;返回BOOL类型的仿函数&#xff09; #include<iostream> #include<string> #includ…

目标检测——YOLOv9算法解读

论文&#xff1a;YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information (2024.2.21) 作者&#xff1a;Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/abs/2402.13616 代码&#xff1a;https://github.com/W…

kubernetes集群svc的代理模式-iptables修改为ipvs

一、概述\ 我们都知道&#xff0c;k8s集群的外部网络分发&#xff0c;借助kube-proxy组件来完成&#xff1b; 问题&#xff1a;我们为什么要将代理模式修改为ipvs而不继续使用iptables呐&#xff1f; 1&#xff0c;iptables底层使用四表五链完成网络代理&#xff0c;效率比较低…

HackCar – 汽车系统的攻击和防御游乐场

现代汽车配备的微控制器使用控制器局域网 (CAN) 来执行安全和豪华功能。 然而&#xff0c;由于CAN网络缺乏速度控制等线控系统的安全性&#xff0c;因此可能会通过消息注入攻击来 劫持车辆&#xff0c;从而造成生命危险。 尽管研究人员努力提出入侵检测、加密和身份验证等解…