Zend Framework 2-使用Memcache/Memocached来存储DB结果


Zend Framework 2 - Using Memcache/Memcached to store DB results

我试图实现memcache来存储Db结果(在tablegateway中),但我遇到了一个问题。如果没有"setItem"answers"getItem"方法,查询工作正常,但如果我使用它们,它会显示以下错误:

An error occurred
An error occurred during execution; please try again later.
Additional information:
PDOException
File:
C:'Program Files (x86)'xampp'htdocs'ZF-Tutorial'vendor'zendframework'zendframework'library'Zend'Serializer'Adapter'PhpSerialize.php:48
Message:
You cannot serialize or unserialize PDOStatement instances

在我的tablegateway里面有一个

namespace Application'Model;
use Zend'Cache'Storage'StorageInterface;
use Zend'Db'TableGateway'TableGateway;
use Zend'Db'Sql'Sql;
use Application'Model'Defaultlanguage;
class AccessoriesTable 
{
    protected $tableGateway;
    protected $cache;
public function __construct(TableGateway $tableGateway)
{
    $this->tableGateway = $tableGateway;
}

public function setCache(StorageInterface $cache)
{
    $this->cache = $cache;
} 

public function fetchAll($lang = null)
{
    if(!isset($lang))  {  
        $lang = DefaultLanguage::LANG;
    }
    if( ($result = $this->cache->getItem('testcache')) == FALSE) {
        $adapter = $this->tableGateway->getAdapter();
        $sql = new Sql($adapter);
        $select = $sql->select();
        $select->columns(array(
            'id',
            'accessories' => $lang
        ));
        $select->from('cat_accessories'); 
        $select->order('accessories ASC');
        $statement = $sql->prepareStatementForSqlObject($select);
        $result = $statement->execute();
        $this->cache->setItem('testcache',  $result);
    }
    return $result; 
}

在我的模块内.php

'Application'Model'AccessoriesTable' =>  function($sm) {
    $tableGateway = $sm->get('AccessoriesTableGateway');
    $cacheAdapter = $sm->get('Zend'Cache'Storage'Memcache');
    $table = new AccessoriesTable($tableGateway);
    $table->setCache($cacheAdapter);
    return $table;
},
'AccessoriesTableGateway' => function ($sm) {
    $dbAdapter = $sm->get('Zend'Db'Adapter'Adapter');
    $resultSetPrototype = new ResultSet();
    $resultSetPrototype->setArrayObjectPrototype(new Accessories());
    return new TableGateway('cat_accessories', $dbAdapter, null, $resultSetPrototype);
},

我试着在我的控制器和视图中使用memcache,效果很好。我不明白错误在哪里。谢谢大家的帮助。

2015年6月28日版

我在这里找到了一个解决方案,效果很好,但我不太喜欢:https://samsonasik.wordpress.com/2012/09/27/zend-framework-2-using-zendcache-and-hydratingresultset-to-save-database-resultset/

内部模块.php

'Application'Model'AccessoriesTable' =>  function($sm) {
    $dbAdapter    = $sm->get('Zend'Db'Adapter'Adapter');
    $cacheAdapter = $sm->get('Zend'Cache'Storage'Memcache');
    $table = new AccessoriesTable($dbAdapter);
    $table->setCache($cacheAdapter);
    return $table;
},

内部配件类别:

namespace Application'Model;
class Accessories 
{
    public $id;
    public $accessories;
    public function exchangeArray($data)
    {
        $this->id     = (!empty($data['id'])) ? $data['id'] : null;
        $this->accessories     = (!empty($data['accessories'])) ? $data['accessories'] : null;
    }   
    public function getArrayCopy()
    {
        return get_object_vars($this);
    }
}

内部附件表:

namespace Application'Model;
use Zend'Db'Adapter'Adapter;
use Zend'Db'ResultSet'HydratingResultSet;
use Zend'Db'TableGateway'AbstractTableGateway;
use Zend'Db'Sql'Select;
use Zend'Cache'Storage'StorageInterface;
use Application'Model'Accessories;
use Application'Model'Defaultlanguage;
class AccessoriesTable extends AbstractTableGateway
{
    protected $table = 'cat_accessories';
    protected $cache;
    public $lang;
    public function __construct(Adapter $adapter)
    {
        $this->adapter = $adapter;
        $this->resultSetPrototype = new HydratingResultSet();
        $this->resultSetPrototype->setObjectPrototype(new Accessories());
        $this->initialize();
    }
    public function fetchAll($lang = null)
    {
        $this->setLang($lang);
        $cacheName = md5('accessories-'.$this->lang);
        if( ($resultSet = $this->cache->getItem($cacheName)) == FALSE) {
            $resultSet = $this->select(function (Select $select){
                $select->columns(array('id', 'accessories'=> $this->lang ));
                $select->order(array($this->lang. ' asc'));  
            });
            $this->cache->setItem($cacheName ,  $resultSet );
        }
        return $resultSet; 
    }
}

新问题:如何使用"传统"表网关结构实现它????

我尝试使用传统的表网关,但错误与上面相同。

内部表网关:

public function fetchAll($lang = null)
{
    $this->setLang($lang);
    $cacheName = md5('accessories-'.$this->lang);
    if( ($resultSet = $this->cache->getItem($cacheName)) == FALSE) {
        $resultSet = $this->tableGateway->select(function (Select $select){
            $select->columns(array('id', 'accessories'=> $this->lang ));
            $select->order(array($this->lang. ' asc'));  
        });
        $this->cache->setItem($cacheName ,  $resultSet );
    }
    return $resultSet; 
}

第一条错误消息中明确指出的主要问题;您正在尝试保存一个PDOStatement实例,该实例是execute()方法的输出。然后,您的缓存后端会自动尝试序列化那个实际上不可序列化的语句实例。

$result = $statement->execute();
$this->cache->setItem('testcache',  $result);

只需从resultset中获取数据并对其进行迭代。在迭代时将数据转换为数组,或者如果项是对象,则通过实现ArraySerializableInterface向该对象添加getArrayCopy()方法,从而轻松提取对象的数组副本并存储到缓存中。

对于大多数场景,用getArrayCopy()方法返回一个简单的关联数组就足够了,例如:

public function getArrayCopy()
{
   return [
       'id' => $this->id,
       'name' => $this->name,
       'bar' => $this->bar,
       'baz' => $this->baz,
   ];
}

这些是错误:

$result = $statement->execute();
$this->cache->setItem('testcache',  $result);

$result变量是一个ResultSet对象,您正试图将其插入memcached(整个对象,而不仅仅是返回数据)中。试着做这个$result->current();,让我知道发生了什么。

编辑:2015年6月28日

由于我给你的链接将在一周后过期,我决定将代码包含在中

/**
 * Create plain mysql queries.
 *
 * @param String $sql the plain query
 * @throws Exception If database is not found or $sql is empty
 * @return array|HydratingResultSet|null
 */
use Zend'Db'Adapter'Adapter;
use Zend'Db'ResultSet'HydratingResultSet;
use Zend'Stdlib'Hydrator'ObjectProperty;
use Zend'Db'Adapter'Driver'Pdo'Result;
public static function createPlainQuery($sql = null)
{
    $dir = dirname(dirname(dirname(__DIR__)));
    if (!is_file($dir.'/config/autoload/local.php')) {
        throw new 'Exception("Could not load database settings");
    }
    if (empty($sql)) {
        throw new 'Exception(__METHOD__ . ' must not be empty');
    }
    $local = require($dir.'/config/autoload/local.php');
    $db = new Adapter($local['db']);
    $stmt = $db->createStatement((string) $sql);
    $stmt->prepare();
    $result = $stmt->execute();
    if ($result instanceof Result && $result->isQueryResult() && $result->getAffectedRows()) {
        $resultSet = new HydratingResultSet(new ObjectProperty(), new 'stdClass());
        $resultSet->initialize($result);
        $resultSet->buffer();
        return ($resultSet->valid() && $resultSet->count() > 0 ? $resultSet->toArray() : null);
    }
    return null;
}