缓存(cache)是一类可以更快的读取数据的介质统称,也指其他可以加快数据读取的存储方式。一般用来存储临时数据,常用介质是读取速度很快的内存。
对于低频变动的页面可以考虑使用缓存技术,减少实际渲染次数,渲染次数少了后,用户得到的响应就会更快
有两个情况用缓存比较常见,一个是视图的渲染,你的页面比较复杂,元素比较多,加载比较慢,这个时候可以先把页面放在缓存中,这样在用户第二次访问的时候就快了。第二个是数据库的查询,你数据库中的内容很多,你可以在用户第一次使用的时候把数据库放在缓存中,这样它第二次用的时候就快了
缓存是可以设置存活时间的,因为我们的页面与数据库内容不是一成不变的,我们可以根据实际情况来设置缓存的存活时间
目录
2.2.5 取不到就存 cache.get_or_set()
2.2.9 批量删除缓存 cache.delete_many()
1 配置缓存
缓存有很多种介质可以存储缓存
1.1 缓存到数据库
1.1.1 配置settings.py
将缓存的数据存在数据库中,虽然还是从数据库拿数据,但缓存数据表中的数据是不多的,所以速度要比直接从总数据表拿数据快
我们在settings.py中需要创建一个字典CACHES
字典中key的意思是
- BACKEND 缓存引擎,数据库缓存我们就这样写就好
- LOCATION 缓存表名称
- TIMEOUT 缓存保存时间,单位为秒。可以不写,不屑默认是300s,如果过了300秒没存进去,这缓存我就不存了
-
OPTIONS 一些选项
- MAX_ENTRIES 缓存表最大数据数,可以不写,不写默认为300条
- CULL_FREQUENCY 当缓存表达到最大数据数时,删除1/x的缓存数据,我上面给的是2,那就是如果我到达了缓存最大数据数的时候,就删除表中1/2的数据
1.1.2 生成缓存数据表
使用之前我们需要在项目数据库中加入缓存数据表 输入 python manage.py createcachetable
之后我们去mysql中查看,发现my_cache_table已经创建完毕
我们看一下这个表的内容
从上至下依次是 缓存键,缓存值,过期时间
1.2 缓存到服务器内存
这个平时用用就可以了,如果是正式上线会将缓存存到缓存性的数据库redis中
- unique-snowflake是雪花算法寻址
1.3 缓存到服务器文件
我在项目路径下创建了一个文件夹cache
1.4 缓存配置可以有多个
缓存可以有多个相同类型或不同类型的缓存,只要名字不同就行
最好是搞一个default的缓存,在引入对象的时候会用到
2 使用缓存
我们下面以缓存到数据库为例
为了测试是否走的是缓存,我们加上一个视图
再加上一个路由
访问这个路由你每一次刷新页面,都会显示访问的时间戳
2.1 整体缓存
整体缓存就是把整个页面都扔到缓存中
2.1.1 视图中使用
我们可以在视图中使用cache_page装饰器,cache_page的参数是该缓存的有效期,单位为秒
如果缓存在有效期内会直接使用缓存的数据,如果不在有效期内会重新走一遍视图获取数据
我们访问一下该路由
再刷新一下
发现时间戳相同,我们的缓存生效了
我们去mysql中查看,发现缓存表中有存储的数据
2.1.2 在路由中使用
屏蔽掉刚刚视图中的缓存装饰器
清空缓存表
在路由加入cache_page,用法与视图中使用相似,第一个参数是过期时间,第二个参数的要缓存的视图
访问一下
刷新一下
时间戳没有变化,缓存生效
数据表中增加了数据
2.2 局部缓存
整体缓存只能缓存某个整体页面,我们没法对整体页面进行操作,局部缓存可以缓存某个变量,局部缓存我们只能在视图中操作
2.2.1 引入cache对象
引入caches,然后通过caches引入settings.py中设置的不同的缓存
2.2.1.2 方法二
引入cache,cache相当于settings.py中的默认项,我们后面对cache直接使用就行了
我们后面就使用方法二引入后操作缓存
2.2.2 设置缓存内容 cache.set()
使用cache.set()的方式存储缓存,返回值无论成功与否都是None,set()有三个参数,依次是
- key 键,需要传入字符串形式
- value 值,任何python变量都可以
- timeout 过期时间,可以不给,如果不给就按settings.py中的cache设置的来,单位为秒
仅仅设置而不使用的话,我们访问后依然是不同的时间戳
但存储的时候在缓存数据库中会有存储的数据
当你使用同一个key存储多次的时候,后面的值会覆盖掉前面的值
2.2.3 取出缓存 cache.get()
参数为key,存储时用的key放在这里就可以拿出来了,如果没有指定的key会返回None
有就用,没有就存,这样我们访问后再刷新,时间戳是相同的
2.2.4 增加缓存 cache.add()
只有在key不存在时cache.add()会生效,如果存储成功则返回True,如果返回失败则返回False
我们如果使用cache.add()增加缓存的话,在上面的逻辑中,你去的时候就不用进行判断了
但是会出现获取不到的情况
这个是因为在程序走到这里的时候,由于之前有该key的cache但所剩的时间极短,所以没添加进去且在后面会获取不到
2.2.5 取不到就存 cache.get_or_set()
有三个参数,依次是
- key 缓存的键
- value 缓存的值
- timeout 过期时间,单位为秒
使用get_or_set()对于上面的逻辑来说不需要进行判断,而且使用get_or_set不会出现获取到None的情况
get_or_set的返回值是设置的value值
2.2.6 批量存储缓存 cache.set_many()
有两个参数,依次是
- dict 要存储的内容,我们把要存储的内容都放到一个字典中
- timeout 过期时间,单位为秒
set_many()存储的数据不能使用get()取,如果用get取是无效的
set_many()会将没有存储成功的数据作为列表返回,如果都成功了就会返回一个空数组
2.2.7 批量提取缓存 cache.get_many()
get_many()的参数为要提取的键列表,get_many()的返回值是一个字典,你需要用get()拿到指定键的内容
像我这样写会出现None的情况
2.2.8 删除缓存 cache.delete()
参数为缓存的key
这样写页面上返回的就永远是None
2.2.9 批量删除缓存 cache.delete_many()
参数为要删除键的数组
这样页面上会永远显示None
3 浏览器缓存
浏览器本身是自带缓存的,分为两大类,强缓存与协商缓存
3.1 强缓存
强缓存不会向服务器发送请求,直接从缓存中读取资源。
3.1.1 前进与后退
一般浏览器,点击后退再前进回来就不会向服务器发送请求
如果你第一次访问的时候,会有响应的信息
但如果访问一个别的地址后再进行后退,则没有响应信息,我们发现时间戳也没变,没有进行请求
3.1.2 整体缓存页面
我们现在使用将页面整体缓存的视图
之后我们访问一下test_cache这个路由
发现在响应头中多了两个值(使用局部缓存没有这两个值),这两个值都是控制缓存的时间的,Cache-Control是相对时间,Expires是绝对时间,两者同时存在优先使用Cache-Control
3.2 协商缓存
协商缓存的内容是静态文件,大图片这种大型文件
当这些大文件缓存到期后,与服务器进行通信,如果服务器那边有要求更改就重新获取文件,如果没有要求更改就保留原来的缓存,优点是不用每次缓存到期都拿新的
这个一般有两种方式,视频中也没说怎么实现,我们简单了解一下就行
1.Last-Modified响应头与If-Modified-Sine请求头
- Last-Modified为文件最近的修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存
- 当缓存到期后,浏览器将获取到Last-Modified值作为请求头If-Modified-Since的值,与服务器发请求协商,服务端返回304响应码(响应体为空),代表缓存继续使用,200响应码代表缓存不可用(响应体为最新资源)
2.ETage响应头和If-None-Match请求头
- ETage是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,ETag就会重新生成
- 缓存到期后,浏览器将ETag响应头的值作为If-None-Match请求头的值,给服务器发请求协商;服务器接到请求头后,对比文件标识,不一致则认为资源不可用,返回200响应码(响应体为最新资源);可用则返回304响应码
第一种方式是算时间,第二种方式是算哈希值,哈希值会比算时间多占用一些计算资源,如果这两种方案同时出现浏览器优先使用ETag