CakePHP 查询结果缓存
CakePHP Query results caching
最近我将 CakePHP 3.2
项目移至虚拟主机(CentOS
、php 7.0/5.6
都尝试了,OpCache
已启用),发现查询结果缓存不起作用.
我使用导航菜单的默认文件缓存引擎。
$mt = TableRegistry::get('MenuItems');
$menu = $mt->find('active')
->select([
"MenuItems.id",'Nodes.id','title', 'header', 'route', 'link',
'parent_id' => 'Nodes.parent_id' ])
->orderAsc('Nodes.num')
->cache("sitemenu_MenuItems", 'long')
->hydrate(false)
->toArray();
我在本地 OpenServer
、IIS7
和 IIS8
服务器以及其他 Linux
服务器上使用此代码没有问题。
那么,发生了什么:
当我第一次运行编写脚本时,cake从数据库中获取数据并将缓存写入/src/tmp/cache/long/cake_sitemenu__menu_items
。文件已像往常一样序列化内容。
但是当我刷新页面时,我看到的结果是空的。
错误或调试日志中没有任何内容。
我试过将缓存键小写,但没有成功。
有什么想法吗?
我添加了测试代码来检查基本缓存本身:
public function qwe(){
$data = ['key' => 'value'];
//Cache::write('test', $data, 'long');
$result = Cache::read('test', 'long');
$result[] = 'xxx';
$this->setJsonResponse($result);
}
此代码 returns 正确结果。
到目前为止,我发现 Cake\Cache\Egine\FileEngine
class 的 read()
方法存在一些问题。第 223 行:
$data = unserialize((string)$data);
$data
在调用主机和本地计算机之前具有相同的值。然后 unserialize
returns ResultSet
空 items
字段的对象;
SplFixedArray
和 unserialize
好像有点问题
如您所见,在调试过程中我发现问题是由 ResultSet
使用的 SplFixedArray
和 unserialize()
引起的。
之后我找到了this topic: PHP 7.0.15 and PHP 7.1.0 ResultSet Caching #10111。
在我的例子中,我尝试使用 PHP 7.0.24
、7.1.5
、5.6.30
和 5.5.38
。 5.5 效果很好。
这个问题在那个话题的讨论中被解决了,所以我从CakePHP 3.5
复制了ResultSet::serialize
和unserialize
方法。诀窍是将数据序列化为通常的数组,而不是 SplFixedArray
。
\Cake\ORM\ResultSet
313: public function serialize()
314: {
315: if (!$this->_useBuffering) {
316: $msg = 'You cannot serialize an un-buffered ResultSet. Use Query::bufferResults() to get a buffered ResultSet.';
317: throw new Exception($msg);
318: }
319:
320: while ($this->valid()) {
321: $this->next();
322: }
323:
324: if ($this->_results instanceof SplFixedArray) {
325: return serialize($this->_results->toArray());
326: }
327:
328: return serialize($this->_results);
329: }
330:
339: public function unserialize($serialized)
340: {
341: $results = (array)(unserialize($serialized) ?: []);
342: $this->_results = SplFixedArray::fromArray($results);
343: $this->_useBuffering = true;
344: $this->_count = $this->_results->count();
345: }
最近我将 CakePHP 3.2
项目移至虚拟主机(CentOS
、php 7.0/5.6
都尝试了,OpCache
已启用),发现查询结果缓存不起作用.
我使用导航菜单的默认文件缓存引擎。
$mt = TableRegistry::get('MenuItems');
$menu = $mt->find('active')
->select([
"MenuItems.id",'Nodes.id','title', 'header', 'route', 'link',
'parent_id' => 'Nodes.parent_id' ])
->orderAsc('Nodes.num')
->cache("sitemenu_MenuItems", 'long')
->hydrate(false)
->toArray();
我在本地 OpenServer
、IIS7
和 IIS8
服务器以及其他 Linux
服务器上使用此代码没有问题。
那么,发生了什么:
当我第一次运行编写脚本时,cake从数据库中获取数据并将缓存写入/src/tmp/cache/long/cake_sitemenu__menu_items
。文件已像往常一样序列化内容。
但是当我刷新页面时,我看到的结果是空的。
错误或调试日志中没有任何内容。
我试过将缓存键小写,但没有成功。
有什么想法吗?
我添加了测试代码来检查基本缓存本身:
public function qwe(){
$data = ['key' => 'value'];
//Cache::write('test', $data, 'long');
$result = Cache::read('test', 'long');
$result[] = 'xxx';
$this->setJsonResponse($result);
}
此代码 returns 正确结果。
到目前为止,我发现 Cake\Cache\Egine\FileEngine
class 的 read()
方法存在一些问题。第 223 行:
$data = unserialize((string)$data);
$data
在调用主机和本地计算机之前具有相同的值。然后 unserialize
returns ResultSet
空 items
字段的对象;
SplFixedArray
和 unserialize
如您所见,在调试过程中我发现问题是由 ResultSet
使用的 SplFixedArray
和 unserialize()
引起的。
之后我找到了this topic: PHP 7.0.15 and PHP 7.1.0 ResultSet Caching #10111。
在我的例子中,我尝试使用 PHP 7.0.24
、7.1.5
、5.6.30
和 5.5.38
。 5.5 效果很好。
这个问题在那个话题的讨论中被解决了,所以我从CakePHP 3.5
复制了ResultSet::serialize
和unserialize
方法。诀窍是将数据序列化为通常的数组,而不是 SplFixedArray
。
\Cake\ORM\ResultSet
313: public function serialize()
314: {
315: if (!$this->_useBuffering) {
316: $msg = 'You cannot serialize an un-buffered ResultSet. Use Query::bufferResults() to get a buffered ResultSet.';
317: throw new Exception($msg);
318: }
319:
320: while ($this->valid()) {
321: $this->next();
322: }
323:
324: if ($this->_results instanceof SplFixedArray) {
325: return serialize($this->_results->toArray());
326: }
327:
328: return serialize($this->_results);
329: }
330:
339: public function unserialize($serialized)
340: {
341: $results = (array)(unserialize($serialized) ?: []);
342: $this->_results = SplFixedArray::fromArray($results);
343: $this->_useBuffering = true;
344: $this->_count = $this->_results->count();
345: }