美文网首页Laravel Tips
怎样快速的使用缓存 Cache

怎样快速的使用缓存 Cache

作者: xzing | 来源:发表于2018-06-15 21:03 被阅读10次

    最近看到了几种加缓存的方法,整理对比一下。

    拿一个case来说,我们要去数据库取一条用户记录,迫于性能,还要加一层缓存。我们针对这个问题看看几种使用姿势的对比。

    Laravel 中 Facades 做法

    $person = Cache::remember("person.{$id}", 5, function () use ($id) {
        return PersonDao::find($id);
    });
    

    Spring Cache 的做法

    @Cache(key = "person#id", ttl = 5)
    public Person getPerson(Integer id) {
        return PersonDao.find(id);
    }
    
    Person person = repository.getPerson();
    

    备注:

    • PersonDao.find 表示从DB里去拿数据

    这两种方法看起来都很简单,除了必要的语法格式,你需要写的代码就是:

    • cache 函数或标记,表明需要缓存
    • key 不解释
    • ttl 不解释
    • func… 回源数据

    基本上可以说是要啥写啥了,不啰嗦。

    其实 Php 和 Java 的语法很接近,两种方法在两种语言里都适用。不过 Php 需要第三方的注解支持;Java 需要 8 以上来支持 lambda。

    简单的东西一定面临扩展性的问题,我们来看一看他们的可能性。

    如果我们要更换缓存驱动怎么办?

    Laravel

    Cache::store('redis')->remember(...)
    

    Spring

    @Cache(driver = redisCache.class)
    

    依然很简单。

    有些时候,在使用 redis 作为缓存的时候,我们会用不同的编码

    Laravel

    Cache::store('redis')->encoding('json')->remember(...)
    

    Spring

    @Cache(encoding = JsonEncoding.class)
    

    方法其实是相似的,一般的,Lavavel 利用自己习惯的链式操作和 Php 的不定参数,可以让你随时传入自己个性化的需求。Spring 也利用 Annotation 来实现类似的效果。

    更多的,Laravel 和 Spring Boot 都遵循了约定优于配置的原则,使得在大多数情况下,你都不需要传这些,只需要使用全局的默认配置就能满足需求。也就是上面的最方便的办法。

    简单的方法介绍完了,我们来聊聊 Go 里的做法

    刚刚接手一个 Go 项目,里面看到是这样处理缓存的:

    proxy := Proxy{
        Prefered: RedisAdapter{
            RedisClient
        },
        Backup: DaoAdapter{
            PersonDao
        }
    }
    person := proxy.Get('xxx').(Person)
    

    是不是一下看懵逼了,我也是,这还是简化的版本。真正实现一个这样的功能,大约新增了三个实现了数个空接口新类和几个方法。

    更蛋疼的,这三个类都是类型相关的,换句话说,list/detail 两种功能各自都需要3个类,换个 model 也不能复用。更悲催的,因为 IDE 对 Go 的 interface 分析都不太好,当你阅读别人的代码的时候,你完全不知道哪里是哪里。

    所以,这里想尝试一下,能否在 Go 里使用上面的简单方法处理缓存。

    id := 9
    
    person := remember("key", 30 * time.Second, func() interface{} {
        return PersonDao.find(id)
    }).(*Person)
    
    // 或者更 Go 一点
    
    var person Person
    remember(&person, "key", 30 * time.Second, func(iface interface{}) {
        *iface.(*Person) = *PersonDao.find(id)
    })
    

    比较烦的是,Go 不支持泛型,定义函数的时候要尽可能少依赖类型。常用的办法是把类型传入。

    前者看起来简单,但有个很要命的地方,你需要很严格的把 Person 类进行序列化。否则从 cache 里取出来后类型可能会丢,导致断言失败。

    那么,第二种办法可以吗?或者说,在 Go 里能不能通过简单标记的办法来实现多态?

    我只能说,不好弄。

    Spring 里很多注解效果,都是靠动态代理实现的(相当于 Php 里阉割版的 __call )。但遗憾的是,Go 目前不能支持这一特性。如果要硬上的话,也可以,搞出来可能跟我接的代码挺像的。

    相关文章

      网友评论

        本文标题:怎样快速的使用缓存 Cache

        本文链接:https://www.haomeiwen.com/subject/yvxveftx.html