在业务中涉及操作两个数据库的查询操作, 一定会面临数据一致性的问题。 Mysql中数据可能是最实时的,redis会延后30s。牺牲数据的实时性来换取查询性能。
短时间缓存:解决高并发带来的数据库查询压力,缓存的生命周期定义在业务合理的范围内
长时间缓存:将长时间不会发生任何更改的查询结果缓存起来,减少了查数据库的操作,提高了性能。
pip install django-redis
安装这个库需要django版本大于2.2
# settings.py
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/3', #redis默认有16个库,后面数字可设定使用几号库
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient'
}
},
}
python manage.py createcachetable
python manage.py shell
>>> from django.core.cache import cache
>>> cache.set("test_key", "test_value")
True
from django.views.decorators.cache import cache_page
# 给函数加上装饰器,参数为缓存的秒数
@cache_page(60 * 15)
def my_view(request):
...
# 类缓存写法
from django.utils.decorators import method_decorator
# 此方法会给所有类方法添加缓存
@method_decorator(cache_page(60 * 15), name='dispatch')
class MyView(View):
def get(self, request, pk):
...
pass
# 此方法给类方法单独添加缓存
class MyView(View):
@method_decorator(cache_page(60 * 15))
def get(self, request, pk):
...
pass
from django.core.cache import cache
redis_key = "archive_cache"
redis_value = ...
cache.set(redis_key, json.dumps(redis_value))
# 设置缓存时长
cache.expire(redis_key, 30)
cache.get(redis_key)
若要将对象进行缓存,需要将对象转换为json存到redis缓存中,然后从redis缓存中获取json数据,再反序列化为对象
article_list = Article.objects.all()
archive_dict = {}
for article in article_list:
year = article.create_time.strftime("%Y")
# 如果当前字典没有目标key, 则给定默认值
# 如果当前字典有目标key, 则无变化
archive_dict.setdefault(year, {"year": year, "article_list": []})
archive_dict[year]['article_list'].append(article)
context = {
"archive_list": archive_dict.values(),
"article_count": len(article_list)
}
# 缓存archive_list
serializer_archives = []
for archive in archive_dict.values():
serializer_archives.append({
"year": archive['year'],
"article_list": serializers.serialize("json", archive['article_list'])
})
cache.set(redis_key, json.dumps(serializer_archives))
cache.expire(redis_key, 30)
redis_value = cache.get(redis_key)
if redis_value:
print("hit cache")
serializer_archives = json.loads(redis_value)
archive_list = []
article_count = 0
for archive in serializer_archives:
# 为了模板可以正常渲染, 需要将article反序列化为对象
archive_list.append({
"year": archive['year'],
"article_list": [obj.object for obj in serializers.deserialize('json', archive['article_list'])]
})
article_count += len(archive['article_list'])
context = {
"archive_list": archive_list,
"article_count": article_count
}
这里的缓存存取方式略显繁琐,可以引入django rest framework配合使用,序列化器简单强大,灰常好用,可以看鄙人的另一篇文章https://blog.csdn.net/Runaway_pilot
django-redis 支持永不超时的设置。
cache.set("key", "value", timeout=None)
在 redis 中,我们可以获取任何 key 的 ttl(time to live), django-redis 也同样支持获取 ttl
以 keys 搜索过期:
>>> from django.core.cache import cache
>>> cache.set("foo", "value", timeout=25)
>>> cache.ttl("foo")
25
>>> cache.ttl("not-existent")
0
使用 persist 可以让一个值永久存在
使用 persist 的例子:
>>> cache.set("foo", "bar", timeout=22)
>>> cache.ttl("foo")
22
>>> cache.persist("foo")
>>> cache.ttl("foo")
None
使用 expire 可以指定一个新的过期时间
使用 expire 的例子:
>>> cache.set("foo", "bar", timeout=22)
>>> cache.expire("foo", timeout=5)
>>> cache.ttl("foo")
5
django-redis 支持使用全局通配符的方式来检索或者删除键。
使用通配符搜索的例子
>>> from django.core.cache import cache
>>> cache.keys("foo_*")
["foo_1", "foo_2"]
这个写法会返回所有匹配的值。但在拥有很大数据量的数据库中这样做并显然不太合适。
使用 iter_keys
取代 keys
方法, iter_keys
将返回匹配值的迭代器, 然后我们可以使用迭代器高效地进行遍历。
>>> from django.core.cache import cache
>>> cache.iter_keys("foo_*")
>>> next(cache.iter_keys("foo_*"))
"foo_1"
如果要删除键,使用 delete_pattern
方法,它也支持全局通配符, 它会会返回删掉的键的数量
>>> from django.core.cache import cache
>>> cache.delete_pattern("foo_*")
2
https://django-redis-chs.readthedocs.io/zh_CN/latest/