轮播图接口加缓存
接口加缓存
以轮播图为例,但是轮播图其实用不到缓存因为轮播图很少更新。这个并不是什么紧急的东西。不影响用户的体验,数据实时性。
为什么接口要加缓存
如果是一个互联网项目轮播图在同一个网址的首页,如果一瞬间有很多访问量,轮播图的接口就会被执行很多次,而轮播图是从mysql里查询出来的,瞬间访问量过大很可能导致接口崩溃。
优化查询,访问来了先去缓存中找,没有再去sql里找,在把轮播图数据放到缓存中。后面的查询都可以在redis中查询。
代码
重写drf list方法在内部写逻辑后给接口继承
from rest_framework.mixins import ListModelMixin
from utils.common_response import APIResponse
from django.core.cache import cache
class CommonListBannerModelMixin(ListModelMixin):
cache_key = None
def list(self, request, *args, **kwargs):
# 拿到缓存中的数据
data = cache.get(self.cache_key)
# 判断是否存在
if data:
# 有直接返回
return APIResponse(data=data)
else:
# 不存在则去数据库里查
res = super().list(request, *args, **kwargs)
# 查出来以后存入缓存,便于后面访问接口从缓存中拿
cache.set(self.cache_key, res.data)
return APIResponse(data=res.data)
查看轮播图接口
from django.shortcuts import render
# Create your views here.
from rest_framework.viewsets import GenericViewSet
from .models import Banner
from .serializer import BannerSerializer
from utils.common_ListBannerModelMixin import CommonListBannerModelMixin
class BannerView(GenericViewSet, CommonListBannerModelMixin):
queryset = Banner.objects.filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = BannerSerializer
cache_key = 'banner_list'
但是,有一个严重的问题,这个时候如果我们的数据库中轮播图数据有变化,但是我们redis缓存中已经有了之前的数据,修改数据库数据,缓存中并没有影响。导致数据不一致。
双写一致性
解决数据不一致问题
- mysql数据修改后,删除缓存。
- 修改数据,更新缓存。
- 定时任务,隔一段时间更新一次缓存。 (这个不太好,实时性差,但是可以用在不是很重要的接口上)
使用celery来做
代码
在celery包里创建一个新任务,home_task
from .celery import app
from home.models import Banner
from home.serializer import BannerSerializer
from django.core.cache import cache
from django.conf import settings
# 更新缓存轮播图任务
@app.task
def update_banner():
# 拿出轮播图数据
banners = Banner.objects.filter(is_delete=False,is_show=True).order_by('orders')
# 序列化
ser =BannerSerializer(instance=banners,many=True)
# for循环拿出对象
for item in ser.data:
# 修改自己拼接后的地址
item['image'] = settings.BACKEND_URL + item['image']
cache.set('banner_list',ser.data)
return True
轮播图不显示的原因是没有request对象就不会带上前缀,自己加上
settings/dev.py
# 后端地址
BACKEND_URL= 'http://127.0.0.1:8001'
在celery里写一个定时任务
from celery import Celery
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
# 中间件 用本地的redis 1库,提交的任务放在里面
broker ='redis://127.0.0.1:6379/1'
# 执行结果 用本地的redis 2库,执行完的结果放在里面
backend ='redis://127.0.0.1:6379/2'
# 实例化得到对象,并起个名字可以__name__获得这个文件的名字 include 指定管理的任务
app = Celery('test',broker=broker,backend=backend,include=['celery_task.order_task','celery_task.user_task','celery_task.home_task'])
from datetime import timedelta
# 定时任务
# celery的配置文件#####
# 第一步:在celery的py文件中写入
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False
# 任务的定时配置
app.conf.beat_schedule = {
'update_banner':{
'task':'celery_task.home_task.update_banner',
'schedule': timedelta(seconds=10)
}
}
新写的任务一定要在celery里的include托管
app = Celery('test',broker=broker,backend=backend,include=['celery_task.order_task','celery_task.user_task','celery_task.home_task'])