【问题标题】:PHP Laravel are DB function results cached?PHP Laravel 是否缓存了数据库函数结果?
【发布时间】:2018-12-19 00:58:58
【问题描述】:

菜鸟问题。我正在从事一个涉及与一些遗留软件交互的项目,并且数据库与常规 Laravel 关系不兼容。

如果我在这样的构造函数中定义事物:

public function __construct(array $attributes = array())
{
parent::__construct($attributes);

$this->vatpercentage = $this->customer()->vatpercentage;
$this->vatcode = $this->customer()->vatcode;
$this->partrevision = $this->part()->revision;
$this->unitprice = $this->part()->unitprice;
}

public function part(){
    return Part::findOrFail($this->partnum);
}

public function customer(){
    $traderid = Order::where('id', $this->orderid)->value('traderid');
    return Customer::where('id', $traderid)->where('tradertype', 'C')->first();
}

我需要在构造函数中多次引用customer()、part()等类似函数。每次我引用 $this->customer() 等时都会查询数据库,还是在我第一次引用它时缓存结果,然后用于所有其他时间?基本上我是否通过以这种方式编码而不是设置 $this->customer = $this->customer() 并获取诸如 $this->customer->example 之类的值来进行很多不必要的数据库调用?

【问题讨论】:

  • 第一次在请求中使用它时会被缓存。因此,如果您加载一个页面,它将只运行一次查询。下一页加载,它将再次运行查询。
  • 您可以安装Laravel Debugbar 以跟踪您在每个页面上运行的查询。
  • 没有。你没有做任何事情来缓存结果。每次运行 customer() 时,它都会构建并执行一个新查询。

标签: php database laravel


【解决方案1】:

任何数据库查询或方法调用都不会自动缓存在您的应用程序中,也不应该缓存。 Laravel 和 PHP 不会知道你想如何使用查询或方法。

每次调用 customer() 时,您都在构建和执行一个新查询。如果这是您想要的,您可以轻松地将结果缓存在一个属性中,但您需要注意 $orderid 属性的值:

protected $customerCache;

public function customer()
{
    if ($customerCache) return $customerCache;

    $traderid = Order::where('id', $this->orderid)->value('traderid');
    return $customerCache = Customer::where('id', $traderid)->where('tradertype', 'C')->first();
}

您在构造函数中也执行了太多操作。我强烈建议不要在任何构造函数中执行查询,构造函数应该用于传递依赖关系。您设计它的方式会使单元测试变得非常困难。

【讨论】:

  • 我基本上是在使用构造函数来匹配通常在旧版软件中指定的不是数据库默认值的任何默认值。我应该在控制器中添加这些还是创建一个函数来设置它们?
  • 这取决于你,我只是不建议在那里提出查询。我不知道你的班级是做什么的,但如果你研究单一责任原则,你可能会发现这个班级不需要知道如何从数据库中获取这些值。如果您研究单元测试,您会发现为什么在构造函数中使用查询会使您的类难以测试。
  • 好的,我会看看其他选项。感谢您的帮助。
【解决方案2】:

在 Laravel 4.* 中有一个 remember() 方法处理查询中的缓存。它已从 5.1 中删除,原因是 Eloquent 和查询构建器都没有责任处理缓存。一个非常简化的装饰器类版本,可以处理查询的缓存:

final class CacheableQueryDecorator
{
    private $remember = 60; //time in minutes, switch to load from config or add a setter
    private $query = null;

    public function __construct(Builder $builder)
    {
        $this->query = $builder;
    }

    private function getCacheKey(string $prefix = ''):string
    {
        return md5($prefix . $this->query->toSql() . implode(',', $this->query->getBindings()));
    }

    public function __call($name, $arguments)
    {
        $cache = Cache::get($this->getCacheKey($name), null);
        if ($cache) {
            return $cache;
        }
        $res = call_user_func_array([$this->query, $name], $arguments);
        Cache::put($this->getCacheKey($name), $res, $this->remember);
        return $res;
    }
}

使用它:

$results = (new CacheableQueryDecorator($query))->get()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-17
    • 2010-11-13
    • 1970-01-01
    • 2019-01-21
    相关资源
    最近更新 更多