缓存 Laravel 模型的小问题
缓存嵌套关联
最近在公司项目中想要缓存 Laravel 的模型,因为加载了很多嵌套关联的模型,使用 json 系列函数并不能轻松地将 json 重新转回模型对象,所以使用了 serialize 系列函数
$json = $redis->get($cacheKey);
$user = $json ? new User(json_decode($json, true)) : User::find($id);
// 模型没有关联时,可以直接从 json 取得数据填充新模型
$ser = $redis->get($cacheKey);
$user = $ser ? unserialize($ser) : User::with('a.b')->find($id);
反序列化不调用构造方法
起初并没有什么问题,从缓存中取出反序列化后就能像一般的模型正常使用,直到我需要在模型的构造函数中初始化一些属性。因为 unserialize
并不会调用构造方法,所以在访问这些属性时是并未初始化的空值。在反序列化时触发的 __wakeup
魔术方法中也要做属性的初始化操作,完成后问题就解决了
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->srv = new UserService();
}
public function __wakeup()
{
parent::__wakeup();
$this->srv = new UserService();
}
全局静态初始化方法 booted
我之后注意到 Laravel 提供了一个静态的全局初始化方法可供重写 booted
,如果需要初始化的属性可以是静态时,这样做或许更优雅吧
protected static function booted()
{
self::$srv = new UserService();
}
如果 IDE 没有方法提示,可以加注释
/* @var UserService */
static $srv;
调用 refresh 的问题
在拿到缓存的模型后,如果需要重新从数据库读取数据,调用 refresh
只会读取模型本身的关联,不会读取嵌套的关联。需要重新 load
一遍关联,或者在对应模型的 with
数组加入每次需要带上的关联
$user->refresh();
$user->load('a.b');
好像有人也发现了这个问题,提了 issue Eloquent - nested relations lost when calling refresh on model,Dries Vints(Laravel 项目维护者)回复是“这似乎是一个问题而不是 bug,建议到社区讨论”。我想了下,觉得他是对的,因为 with
上面附带的关联时作用于那次查询的,跟查询出来的模型没有关系。不看查询只看模型的话,要重新加载关联,那么只能自己 load
所需的关联,或者在模型的 with
属性带上关联
备注
- Laravel 模型缓存框架有很多,站里也有教程。不过公司用的是原生 PHP,只是我为了方便单独引入 Laravel 的 Eloquent 模型,所以那些缓存框架无法使用
- 我对 Laravel 模型用法的理解可能有偏差,如果有错误请指出,有更好的方法请赐教
本作品采用《CC 协议》,转载必须注明作者和本文链接