Django中缓存的使用

唐裕
2023-12-01

一、服务器缓存策略

缓存定义:缓存是一类可以更快的读取数据的介质统称,也指其他可以加快数据读取的存储方式。一般用来存储临时数据,常用介质的是读取速度很快的内存

意义:视图渲染有一定的成本,数据库的频繁查询过高,所以对低频变动的页面可以考虑使用缓存技术,减少实际渲染次数,用户拿到响应的时间成本会更低

缓存利用场景:

(1)博客列表页

(2)电商商品详情页

场景特点:缓存的地方,数据变动频率较少

1、多种级别的缓存

(1)数据库级别的缓存

在Django中settings.py中进行配置,设置缓存

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',		# 控制缓存保存在哪个表里
        'TIMEOUT': 300,		# 缓存保存时间,单位秒,默认值300
        'OPTIONS': {
            'MAX_ENTRIES': 300,		# 缓存最大数据条数
            'CULL_FREQUENCY': 2,	# 缓存条数达到最大值时,删除1/x的缓存数据
        }
    }
}
(2)将数据缓存到服务器内存中
CACHE = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake'
    }
}

上面测试使用,一般内存级别的缓存可以使用内存级别用作缓存的数据库redis

(3)文件系统级的缓存

把缓存存到系统下的某个文件里,但是这种方式一般也不怎么使用

CACHE = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',	# 这个是文件夹的路径
        # 'LOCATION' : 'c:\test\cache'	# windows下示例
    }
}

2、以数据库级缓存为例进行测试

(1)创建缓存表

在Django中的setttings.py文件中,添加配置,然后在项目目录执行

python3 managy.py createcachetable

然后在数据库可以查看到出来一个my_cache_table这张表

mysql> desc my_cache_table;
+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| cache_key | varchar(255) | NO   | PRI | NULL    |       |
| value     | longtext     | NO   |     | NULL    |       |
| expires   | datetime(6)  | NO   | MUL | NULL    |       |
+-----------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> 
(2)Django中对缓存表的使用

使用cache_page函数,这个cache_page函数相当于在执行视图函数之前先看缓存里面有没有要查的数据,如果有直接读缓存,如果没有就继续往下走视图函数,视图函数走完,再往缓存里视图函数返回的数据

方式一:使用装饰器

from django.views.decorators.cache import cache_page

@cache_page(30)		# 单位秒
def test_cache(request):
    ...

方式二:在路由中修改

from django.views.decorators.cache import cache_page
urlpatterns = [
    path('foo/', cache_page(60)(test_cache)),
]

其实都是一样的

(3)测试缓存是否配置成功

那就修改视图函数test_cache如下

import time
from django.views.decorators.cache import cache_page
@cache_page(15)
def test_cache(request):
    t = time.time()
    return HttpResponse('time is %s' % t)

因为使用了缓存,按道理页面中的时间应该不是实时变化的,而是缓存中的,可以在页面中查看效果验证确实如此

3、数据库级缓存-局部缓存(缓存api)

(1)局部缓存的概念

之前的cache_page算是全局缓存,因为是放在视图函数前边,所以是把视图函数返回的数据全缓存,而且这种使用cache_page的方式往缓存里存放的缓存内容并不是键值对的方式进行存放的,也没有专门删除特定缓存的方法,除非缓存全删,所以cache_page这种方式的缓存虽然使用上很简单但是却有明显的缺点,因此还有局部缓存的方式

比如下面这个例子

from django.shortcuts import render
def index(request):
    book_list = Book.objects.all()
    ...
    return render(request, 'index.html', locals)

从上面代码可以看出来,最主要的可能耗时的是book_list这个列表查询,显然只缓存这个数据要比缓存整个视图函数的返回结果要好一点,甚至其他视图函数还可以使用这里缓存的book_list这份数据,复用性也强了,那么Django中可以使用缓存api的方式来进行局部缓存

先引入cache对象

方式一:使用caches[‘CACHES配置项中的key’]导入具体对象

from django.core.cache import caches
cache1 = caches['myalias']			# 这里的myalias是settings.py中CACHES配置项里键值对中的键,当然配置项里可以对多个应用配置不同的配置项
# cache1是缓存对象
cache2 = caches['myalias_2']

方式二:直接引入CACHES配置项中的’default’项

from django.core.cache import cache		# 最后import的cache不加s的话,会使用CACHES配置项中默认的default配置来进行缓存

上面不管哪种方式,操作缓存时都是操作缓存对象,使用第二种方式走默认default配置时,缓存对象名字叫cache

(2)缓存api的使用

1、存储缓存

使用cache.set(key, value, timeout)来进行缓存

key为缓存的key,value为python对象,timeout为缓存的存储时间(单位s秒),默认为CACHES中的TIMEOUT值,返回值为None

2、获取缓存

使用cache.get(key)来进行缓存的获取

key为缓存时保存使用的key,返回值为key的具体值,如果没有数据则返回None

3、存储缓存-在key不存在时生效

使用cache.add(key, value)进行缓存的存储,只在key不存在时才生效

如果存储成功,返回值为True,如果失败返回值为False

4、若未获取到数据则执行set

使用cache.get_or_set(key, value, timeout)方法来获取数据,如果没有找到数据,则执行set操作来缓存数据

返回值为value

5、批量存储缓存

使用cache.set_many(dict, timeout)方法来批量缓存

dict为key和value的字典,timeout为存储时间(s),返回值为插入不成功的key的数组

因此这样就可以控制缓存中的每一份数据了,在视图函数中,在想要查询某些低频数据时,可以先判断,用cache.get看一下缓存里是否有数据,有则从缓存取出,如果没有则正常走视图函数中的查询语句,查出来的结果再使用cache.set缓存一份数据

二、浏览器缓存策略

因为数据通过网络传输也是需要时间的,那么对用重复请求的数据,在浏览器中也可以进行缓存,缓存在客户端而不是服务器

浏览器 浏览器缓存 服务器 第一次发起HTTP请求 没有该请求的缓存结果和缓存标识 发起HTTP请求 返回该请求结果和缓存规则 将该请求结果和缓存标识存入浏览器缓存中 浏览器 浏览器缓存 服务器

浏览器缓存有两大类,一个强缓存,一个协商缓存

1、强缓存

不会向服务器发送请求,直接从缓存中读取数据

(1)响应头-Expires

定义:缓存过期时间,用来制定资源到期的时间,是服务器端的具体的时间点

样例:Expires:Thu, 02 Apr 2030 05:14:08 GMT

(2)响应头-Cache-Control

在HTTP/1.1中,Cache-Control主要用于控制网页缓存。比如当Cache-Control:max-age=120代表请求创建时间后的120秒,缓存失效

说明:目前服务器都会带着这两个头同时响应给浏览器,浏览器优先使用Cache-Control

使用了cache_page之后,会自动发送缓存时间到浏览器端

2、协商缓存

强缓存中的数据一旦过期,还需要跟服务器进行通信,从而获取最新数据,如果强缓存的数据是一些静态文件、大的图片呢?

考虑到大图片这类比较费带宽且不易变化的数据,强缓存时间到期后,浏览器会去跟服务器协商,当前缓存是否可用,如果可用,服务器不必返回数据,浏览器继续使用原来缓存的数据,如果文件不可用,则返回最新数据

如果要使用协商缓存这个策略,那么需要使用Last-Mofified响应头和If-Modified-Since请求头

(1)Last-Modified

Last-Modified为文件的最近修改时间,浏览器第一次请求静态文件时,服务器如果返回Last-Modified响应头,则代表该资源为需协商的缓存

当缓存到期后,浏览器将获取到的Last-Modified值作为请求头If-Modified-Since的值,与服务器发请求协商,服务器返回304响应码[响应体为空],代表缓存继续使用,200响应码代表缓存不可用[响应体为最新资源]

也就是说,协商缓存是在强缓存的基础上多了一个Last-Modified头,会在缓存到期了之后,会跟服务器先商量一下,根据商量的结果来看缓存该怎么处理,Last_modified其实不是最好的方式,后来又有了新的浏览器缓存方式,使用Etag和If-None-Match

(2)Etag

之所以Last-Modified这种方式不太好,是因为其判断文件是否存在的单位标准是秒,但有时候一秒内就有多个文件发生变化

Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成,比如利用哈希值),只要资源有变化,Etag就会重新生成

缓存到期后,浏览器将Etag响应头的值作为If-None-Match请求头的值,给服务器发请求协商,服务器接到请求头后,对比文件标识,不一致则认为资源不可用,返回200响应码[响应体为最新资源],可用则返回304响应码

 类似资料: