【问题标题】:How would you forget cached Eloquent models in Laravel?你怎么会忘记 Laravel 中缓存的 Eloquent 模型?
【发布时间】:2013-11-01 19:12:27
【问题描述】:

关于 Laravel 的理论问题在这里。

所以我要做的缓存示例是:

Article::with('comments')->remember(5)->get();

理想情况下,我希望有一个文章更新事件,当该模型的实例的 ID(已缓存)更新时,我想忘记该键(即使它是被遗忘的查询的整个结果而不是只有一个模型实例),有可能这样做吗?

如果没有,有什么方法可以合理干净地实现这一点吗?

【问题讨论】:

  • 不是那么理论,顺便说一句。
  • 现在没有答案,但当时是因为没有关于使用 eloquent 缓存键的文档

标签: php caching laravel laravel-4


【解决方案1】:

所以我一直在寻找与 OP 相同的问题的答案,但对解决方案并不满意。所以我最近开始玩这个并查看框架的源代码,我发现remember() 方法接受称为key 的第二个参数,并且由于某种原因它没有记录在他们的site (或我错过了吗?)。

现在的好处是,数据库构建器使用在app/config/cache.php 下配置的相同缓存驱动程序,或者我应该说这里记录的相同缓存系统 - Cache。因此,如果您将 min 和 key 传递给 remember(),您可以使用相同的密钥通过 Cache::forget() 方法清除缓存,事实上,您几乎可以使用 official site 中列出的所有 Cache 方法,例如Cache::get()Cache::add()Cache::put() 等。但我不建议您使用其他方法,除非您知道自己在做什么。

这里有一个例子让你和其他人理解我的意思。

Article::with('comments')->remember(5, 'article_comments')->get();

现在上面的查询结果将被缓存并与article_comments键相关联,然后可以随时使用它来清除它(在我的情况下,我在更新时会这样做)。

所以现在如果我想清除该缓存,无论它记住多少时间。我可以通过调用Cache::forget('article_comments'); 来完成它,它应该可以按预期工作。

希望对大家有帮助:)

【讨论】:

  • 很好的答案,谢谢。对于那些不清楚的人来说,要记住的第一个参数是缓存的分钟数。 laravel.com/api/…
  • 聚会迟到了,但这对我不起作用。不返回任何数据。
  • @Alias 你用的是什么版本的 Laravel?除非他们在我尚未查看的最新版本中进行了一些更改,否则它应该可以正常工作。
  • 在最近的版本中,模型不再内置缓存功能。必须明确缓存模型的结果,而不是作为链接函数的一部分。
【解决方案2】:

我认为一个好方法是像this:

$value = Cache::remember('users', $minutes, function()
{
    return DB::table('users')->get();
});

然后使用Model Observers来检测更新模型的事件

class UserObserver {

    public function saving($model)
    {
        //
    }

    public function saved($model)
    {
        // forget from cache
        Cache::forget('users');
    }

}

User::observe(new UserObserver);

【讨论】:

  • 当我运行 DB::table('users')->get();这不会获得 Eloquent 模型的实例,它只会将查询结果作为通用对象数组获得?我以为我可以返回 Eloquent 模型查询的结果,而不是直接的数据库查询,对吗?
  • 如果你想缓存 Eloquent 对象集合,并且如果你只想存储属性以将其转换为数组,我相信你应该使用 User::whereSomething('something')->get()User::whereSomething('something')->get()->toArray()
【解决方案3】:

目前没有简单的方法。但是我找到了这个解决方法,到目前为止它对我有用。

首先你必须扩展Illuminate\Database\Query\Builder

<?php 

class ModifiedBuilder extends Illuminate\Database\Query\Builder {
    protected $forgetRequested = false;

    public function forget() 
    {
        $this->forgetRequested = true;
    }

    public function getCached($columns = array('*'))
    {
        if (is_null($this->columns)) $this->columns = $columns;

        list($key, $minutes) = $this->getCacheInfo();

        // If the query is requested ot be cached, we will cache it using a unique key
        // for this database connection and query statement, including the bindings
        // that are used on this query, providing great convenience when caching.
        $cache = $this->connection->getCacheManager();

        $callback = $this->getCacheCallback($columns);

        if($this->forgetRequested) {
            $cache->forget($key);
            $this->forgetRequested = false;
        }

        return $cache->remember($key, $minutes, $callback);
    }
}

然后你必须创建一个扩展 Eloquent 模型的新类。

<?php

class BaseModel extends Eloquent {
    protected function newBaseQueryBuilder() {
        $conn = $this->getConnection();

        $grammar = $conn->getQueryGrammar();

        return new ModifiedBuilder($conn, $grammar, $conn->getPostProcessor());
    }
}

现在在创建 Eloquent 模型时,而不是扩展 Eloquent 模型扩展新创建的 BaseModel

现在你可以像往常一样remember查询结果了。

YourModel::remember(10)->get();

当你想丢弃缓存的结果时,你要做的就是

YourModel::forget()->get();

如果你之前记住了结果,那么在清除缓存的结果后,模型会在这段时间内继续记住结果。

希望这会有所帮助。

【讨论】:

  • getCached方法中,$key变量是从哪里初始化的?
  • getCacheInfo()函数中检索,在Illuminate/Database/Query/Builder.php中的generateCacheKey()函数中生成密钥。显然,您可以根据 API 使用remember() 方法设置自己的密钥。然而它似乎在getCacheKey() 函数中被忽略了。
  • 我上面提到的方法对于简单的查询和大多数关系都非常有效。但是,当存在数据透视表时(在多对多关系中,它不会按预期工作。
【解决方案4】:

我正在测试调试模式。所以我发现如果你在构造函数中对 app.debug 进行测试,你就可以清除与键关联的缓存。无需为每个函数复制代码。

class Events {
    public function __construct() {
        if (\Config::get('app.debug')) {
            Cache::forget('events');
        }
    }

    public static function all() {
        $events = \DB::table('events as e')
            ->select('e.*')
            ->where('enabled', 1)
            ->remember(30, 'events')
            ->get();

        return $events;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-09
    • 2017-07-04
    • 1970-01-01
    • 2014-08-13
    • 2015-01-06
    • 2016-08-13
    • 1970-01-01
    • 2022-11-21
    相关资源
    最近更新 更多