mukellef / laravel-eloquent-query-cache
现在,为Laravel Eloquent查询的结果添加缓存变得非常简单。
Requires
- illuminate/database: ^7.30|^8.23
- illuminate/support: ^7.30|^8.23
Requires (Dev)
- laravel/legacy-factories: ^1.1
- mockery/mockery: ^1.4
- orchestra/database: ^5.0|^6.0
- orchestra/testbench: ^5.0|^6.0
- dev-master
- 2.6.0
- 2.5.1
- 2.5.0
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.0
- 2.2.0
- 2.1.0
- 2.0.1
- 2.0.0
- 1.4.0
- 1.3.1
- 1.3.0
- 1.2.1
- 1.2.0
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.x-dev
- 1.0.0
- dev-dependabot/github_actions/actions/checkout-3.4.0
- dev-dependabot/github_actions/actions/cache-3.3.1
- dev-dependabot/github_actions/codecov/codecov-action-3
- dev-laravel-5
This package is not auto-updated.
Last update: 2024-09-26 22:27:41 UTC
README
Laravel Eloquent Query Cache恢复了Laravel很久以前移除的remember()功能。它直接在Eloquent级别上添加缓存功能,使得在数据库查询中使用缓存变得容易。
🤝 支持
Renoki Co.在GitHub上致力于将许多开源项目和有用的项目带给世界。每天开发和维护项目是一项艰苦的工作,但我们热爱它。
如果您在日常工作中使用应用程序,在演示中,爱好项目或甚至学校项目中,请对我们的工作说一些好话或赞助我们的工作。好话会触动我们的脉轮和氛围,而赞助将使开源项目保持活力。
🚀 安装
进入控制台,通过Composer安装此包。
$ composer require rennokki/laravel-eloquent-query-cache
您希望缓存的所有模型都应该使用Rennokki\QueryCache\Traits\QueryCacheable特质。
use Rennokki\QueryCache\Traits\QueryCacheable; class Podcast extends Model { use QueryCacheable; ... }
🙌 使用方法
此包能够跟踪SQL的使用,并将其用作缓存存储中的键,使得按查询进行缓存变得简单。
use Rennokki\QueryCache\Traits\QueryCacheable; class Article extends Model { use QueryCacheable; public $cacheFor = 3600; // cache time, in seconds ... } // SELECT * FROM articles ORDER BY created_at DESC LIMIT 1; $latestArticle = Article::latest()->first(); // SELECT * FROM articles WHERE published = 1; $publishedArticles = Article::wherePublished(true)->get();
在上面的示例中,两个查询在缓存存储中都有不同的键,因此我们处理什么查询无关紧要。默认情况下,除非您指定了$cacheFor的值,否则缓存是禁用的。只要$cacheFor存在且大于0,所有查询都将被缓存。
也可以通过不指定$cacheFor并在查询中调用cacheFor()来为特定查询启用缓存。
$postsCount = Post::cacheFor(60 * 60)->count(); // Using a DateTime instance like Carbon works perfectly fine! $postsCount = Post::cacheFor(now()->addDays(1))->count();
缓存标签 & 缓存失效
一些缓存存储接受标签。如果您计划对缓存的查询进行标记,并在需要时仅失效一些查询,这将非常有用。
$shelfOneBooks = Book::whereShelf(1) ->cacheFor(60) ->cacheTags(['shelf:1']) ->get(); $shelfTwoBooks = Book::whereShelf(2) ->cacheFor(60) ->cacheTags(['shelf:2']) ->get(); // After flushing the cache for shelf:1, the query of$shelfTwoBooks will still hit the cache if re-called again. Book::flushQueryCache(['shelf:1']); // Flushing also works for both tags, invalidating them both, not just the one tagged with shelf:1 Book::flushQueryCache(['shelf:1', 'shelf:2']);
但请注意,指定缓存标签不会改变键存储的行为。例如,以下两个查询,尽管使用了相同的标签,但它们在缓存数据库中存储的键是不同的。
$alice = Kid::whereName('Alice') ->cacheFor(60) ->cacheTags(['kids']) ->first(); $bob = Kid::whereName('Bob') ->cacheFor(60) ->cacheTags(['kids']) ->first();
全局缓存失效
要使特定模型的全部缓存失效,请使用不带标签的flushQueryCache方法。
该包会自动为每个来自模型的查询附加一个标签列表,称为每个查询的基础标签。默认情况下,它是完整的模型类名。
如果您想更改基础标签,您可以在模型中这样做。
class Kid extends Model { use QueryCacheable; /** * Set the base cache tags that will be present * on all queries. * * @return array */ protected function getCacheBaseTags(): array { return [ 'custom_tag', ]; } } // Automatically works with `custom_tag` Kid::flushQueryCache();
完全自动失效
为了加快应用程序中失效的构建,您可以指定模型在记录被创建、更新或删除时自动刷新缓存。
class Page extends Model { use QueryCacheable; /** * Invalidate the cache automatically * upon update in the database. * * @var bool */ protected static $flushCacheOnUpdate = true; }
当您设置$flushCacheOnUpdate变量时,该包会为您的模型附加一个观察者,任何created、updated、deleted、forceDeleted或restored事件都会触发缓存失效。
为了使自动刷新工作,您至少需要一个基础标签。默认情况下,模型有一个基础标签设置。在某些情况下,如果您已用空数组覆盖了
getCacheBaseTags(),它可能无法正常工作。
部分自动失效
在某些情况下,你可能不想使特定模型的整个缓存无效。也许你得到了两个独立运行的查询,只想使其中一个的缓存无效。
为此,请在你的模型中重写 getCacheTagsToInvalidateOnUpdate() 方法
class Page extends Model { use QueryCacheable; /** * Invalidate the cache automatically * upon update in the database. * * @var bool */ protected static $flushCacheOnUpdate = true; /** * When invalidating automatically on update, you can specify * which tags to invalidate. * * @return array */ public function getCacheTagsToInvalidateOnUpdate(): array { return [ 'query1', ]; } } $query1 = Page::cacheFor(60) ->cacheTags(['query1']) ->get(); $query2 = Page::cacheFor(60) ->cacheTags(['query2']) ->get(); // The $query1 gets invalidated // but $query2 will still hit from cache if re-called. $page = Page::first(); $page->update([ 'name' => 'Reddit', ]);
请注意:将 $flushCacheOnUpdate 设置为 true 并未指定要使无效的单独标签将导致 完全自动使无效,因为默认的使无效标签是基础标签,你需要至少一个标签来使无效。
未指定要使无效的标签将回退到基础标签集,从而导致完全自动使无效。
关系缓存
关系只是另一种查询。它们可以在数据库查询之前被拦截和修改。以下示例需要 Order 模型(或与 orders 关系关联的模型)包含 QueryCacheable 特性。
$user = User::with(['orders' => function ($query) { return $query ->cacheFor(60 * 60) ->cacheTags(['my:orders']); }])->get(); // This comes from the cache if existed. $orders = $user->orders;
缓存键
该包会自动生成存储在缓存存储中的所需键。然而,如果缓存存储由其他应用程序和/或模型使用,并且你想更好地管理键以避免冲突,则添加前缀可能很有用。
$bob = Kid::whereName('Bob') ->cacheFor(60) ->cachePrefix('kids_') ->first();
如果没有指定前缀,将使用字符串 leqc。
缓存驱动程序
默认情况下,该特性使用默认的缓存驱动程序。如果你想 强制 使用特定的一个,你可以通过调用 cacheDriver() 来做到这一点。
$bob = Kid::whereName('Bob') ->cacheFor(60) ->cacheDriver('dynamodb') ->first();
禁用缓存
如果你启用了缓存(无论是通过模型变量还是通过 cacheFor 范围),你还可以选择在查询构建器链中禁用它。
$uncachedBooks = Book::dontCache()->get(); $uncachedBooks = Book::doNotCache()->get(); // same thing
等效方法和变量
你可以使用此文档中提供的方法按查询查询,或者你可以在模型中为每个设置默认值;使用按查询查询的方法将覆盖默认值。虽然设置默认值不是强制性的(除了 $cacheFor,它将在 所有 查询上启用缓存),但避免在每个查询上使用链式方法可能很有用。
class Book extends Model { public $cacheFor = 3600; // equivalent of ->cacheFor(3600) public $cacheTags = ['books']; // equivalent of ->cacheTags(['books']) public $cachePrefix = 'books_' // equivalent of ->cachePrefix('books_'); public $cacheDriver = 'dynamodb'; // equivalent of ->cacheDriver('dynamodb'); }
高级
在您的自定义 Builder 类中实现缓存方法
由于此包修改了模型中的 newBaseQueryBuilder(),因此有多个特性修改此功能将导致重叠。
这可能发生在你创建自己的 Builder 类用于其他数据库驱动程序或仅仅为了使你的应用查询构建器更灵活的情况下。
为了解决这个问题,你只需要将 \Rennokki\QueryCache\Traits\QueryCacheModule 特性和 \Rennokki\QueryCache\Contracts\QueryCacheModuleInterface 接口添加到你的 Builder 类中。确保模型将不再使用原始的 QueryCacheable 特性。
use Rennokki\QueryCache\Traits\QueryCacheModule; use Illuminate\Database\Query\Builder as BaseBuilder; // the base laravel builder use Rennokki\QueryCache\Contracts\QueryCacheModuleInterface; // MyCustomBuilder.php class MyCustomBuilder implements QueryCacheModuleInterface { use QueryCacheModule; // the rest of the logic here. } // MyBuilderTrait.php trait MyBuilderTrait { protected function newBaseQueryBuilder() { return new MyCustomBuilder( // ); } } // app/CustomModel.php class CustomModel extends Model { use MyBuilderTrait; } CustomModel::cacheFor(30)->customGetMethod();
生成您自己的键
这是默认键生成函数的样子
public function generatePlainCacheKey(string $method = 'get', string $id = null, string $appends = null): string { $name = $this->connection->getName(); // Count has no Sql, that's why it can't be used ->toSql() if ($method === 'count') { return $name.$method.$id.serialize($this->getBindings()).$appends; } return $name.$method.$id.$this->toSql().serialize($this->getBindings()).$appends; }
在某些情况下,例如实现用于 MongoDB 的自定义 Builder,你可能不想使用 toSql() 并使用你自己的方法生成每个 SQL 键。你可以通过重写 MyCustomBuilder 类的 generatePlainCacheKey() 来实现这一点。
然而,强烈建议尽可能使用该函数提供的变量,以避免缓存重叠问题。
class MyCustomBuilder implements QueryCacheModuleInterface { use QueryCacheModule; public function generatePlainCacheKey(string $method = 'get', string $id = null, string $appends = null): string { $name = $this->connection->getName(); // Using ->myCustomSqlString() instead of ->toSql() return $name.$method.$id.$this->myCustomSqlString().serialize($this->getBindings()).$appends; } }
为其他函数实现缓存而不是 get()
由于 Laravel Eloquent 的所有函数都基于它,因此该包提供的构建器仅替换 get()。
use Illuminate\Support\Arr; class Builder { public function get($columns = ['*']) { if (! $this->shouldAvoidCache()) { return $this->getFromQueryCache('get', Arr::wrap($columns)); } return parent::get($columns); } }
如果想要缓存自定义构建器或例如 count() 方法,它不依赖于 get(),你可以使用此语法替换它。
class MyCustomBuilder { public function count() { if (! $this->shouldAvoidCache()) { return $this->getFromQueryCache('count'); } return parent::count(); } }
实际上,如果您使用$this->shouldAvoidCache()检查并使用getFromQueryCache()方法检索缓存数据,您也可以替换构建器中的任何优雅的方法。传递方法名作为字符串,以及可选的列数组,默认为['*']。
请注意,getFromQueryCache()方法接受一个方法名和一个$columns参数。如果您的类没有实现$columns,请勿传递它。
请注意,某些函数如getQueryCacheCallback()可能带有$id参数。该包的默认行为不使用它,因为查询构建器默认使用->get(),它只接受列。
但是,如果您的构建器替换了像find()这样的函数,则需要$id,并且您还需要像这样替换getQueryCacheCallback()
use Illuminate\Support\Arr; class MyCustomBuilder { public function getQueryCacheCallback(string $method = 'get', $columns = ['*'], string $id = null) { return function () use ($method, $columns, $id) { $this->avoidCache = true; // the function for find() caching // accepts different params if ($method === 'find') { return $this->find($id, $columns); } return $this->{$method}($columns); }; } public function find($id, $columns = ['*']) { // implementing the same logic if (! $this->shouldAvoidCache()) { return $this->getFromQueryCache('find', Arr::wrap($columns), $id); } return parent::find($id, $columns); } }
🐛 测试
vendor/bin/phpunit
🤝 贡献
有关详细信息,请参阅CONTRIBUTING。
🔒 安全性
如果您发现任何与安全性相关的问题,请通过电子邮件alex@renoki.org联系,而不是使用问题跟踪器。