缓存方式扩展,缓存 Tag(命名空间) 的实现

用过 Ruby on Rails 以后,从里面学到了很多很不错的应用,如《在 Asp.net 中实现类似 Rails 的 Flash[:notice] 的功能》,这里我实现缓存标签(也可以叫缓存命名空间)。

我们经常会遇到需要批量删除某一类的缓存,如 posts/p/1,posts/p/2,posts/p/3 这几个 CacheKey 都是属于文章列表的,我们想通过 posts 来删除所有页的缓存,这个就是简单的 Get Set Delete 这类的功能操作的了。

Ruby on Rails 里面,缓存可以用 posts/p/* (正则的方式) 来删除一系列的缓存,我这里没有做那么复杂,只是简单的实现给 Caches 加标签,分类,在按照分类来删除一些列缓存。

我这里是模仿的 Django 的一个实现,看这个地址《Setting and deleting cache in Django with tags》,这个的实现方式我整理了一下,做到了 Pulog 里面,代码在这里

看看我在.NET 里面的实现

Caches 类源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Cache 接口,实现 tag 功能,key 前缀
 * Logs,Memcached 在这里没有公开,只是一些具体的实现,你可以根据已经情况实现一下
 * Logs.Debug 表示写 debug 日志
 * Memcached 里面的 Get,Set,Remove 也需要自已实现
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class Caches
{

    private static string GenerateKey(string key)
    {
        return "project_name/" + key;
    }

    ///
    /// 取缓存
    ///
    ///
    ///
    public static object Get(string key)
    {
        key = GenerateKey(key);

        object obj = Memcached.Get(key);

        if (obj != null)
        {

            Logs.Debug("Cache hit " + key);
        }

        return obj;
    }

    ///
    /// 存缓存
    ///
    ///
    ///
    public static void Set(string key, object value)
    {
        key = GenerateKey(key);

        Memcached.Caches.Set(key, value);

        Logs.Debug("Cache set " + key);
    }

    ///
    /// 存缓存,带 Tag,用于做类似命名空间的管理
    ///
    ///
    ///
    ///
    public static void Set(string key, object value, string[] tags)
    {
        if (tags.Length == 0)
        {
            Set(key, value);
        }

        for (int i = 0; i < tags.Count(); i++)
        {
            tags[i] = "tags/" + tags[i];
        }

        List<string> tagList = new List<string>();
        foreach (string tag in tags)
        {
            object tagObj = Get(tag);
            if (tagObj != null)
            {
                tagList = (List<string>)tagObj;
            }

            tagList.Add(key);
            Set(tag, tagList);
        }

        Set(key, value);
    }


    ///
    /// 删缓存
    ///
    ///
    public static void Remove(string key)
    {
        key = GenerateKey(key);

        Memcached.Remove(key);

        Logs.Debug("Cache remove " + key);
    }

    ///
    /// 根据 Tag 删除缓存
    ///
    ///
    public static void RemoveByTags(string[] tags)
    {
        for (int i = 0; i < tags.Count(); i++)
        {
            tags[i] = "tags/" + tags[i];
        }

        List<string> tagList = new List<string>();
        foreach (string tag in tags)
        {
            object tagsObj = Get(tag);
            if (tagsObj != null)
            {
                tagList = (List<string>)tagsObj;
                foreach (string key in tagList)
                {
                    Remove(key);
                }
            }

            Remove(tag);
        }
    }
}

使用的时候

1
2
3
4
5
6
7
8
9
10
11
//写缓存
Caches.Set("posts/p/1",posts,new string[]{ "posts" });  //第 1 页 写缓存
Caches.Set("posts/p/2",posts,new string[]{ "posts" });  //第 2 页 写缓存
Caches.Set("posts/p/3",posts,new string[]{ "posts" });  //第 3 页 写缓存


//取
Caches.Get("posts/p/1"); //取 第 1 页

//删除所有页
Caches.RemoveByTags(new string[]{"posts"});

这个 Tag 也就类似博客系统的 Tag 功能,给 Cache 设定 1 个或多个 Tag,删除的时候就可以根据 Tag 删除 Tag 下面所有 CacheKey 的缓存。