我试图用Memcache中的函数扩展我的PDO类。特别是,我创建了一个调用cache_execute的函数,该函数允许我首先检查缓存中是否存在结果,然后返回缓存中的信息,如果缓存中还不存在信息,则返回数据库中的信息(如果还不存在,则将信息放入缓存中)。
下面是我当前代码的一个示例:
namespace trf;
class StatementWithCaching extends \PDOStatement {
public $db;
public $cache;
protected function __construct(&$db) {
$this->db =& $db;
}
function cache_execute( $array = NULL , $cache = FALSE , $cacheTime = 1800 ) {
if( is_a( $cache , 'Memcache' ) ) {
$query = $this->queryString;
foreach ($array as $key => $value) {
$query = str_replace(':' . $key , "'" . addslashes( $value ) . "'", $query );
}
try {
$memResults = $this->mconn->get( md5( $this->queryString ) );
}
catch ( \Exception $e ) {
$memResults = FALSE;
}
} else {
}
}
}我的问题是-如何将从缓存中检索到的信息放在PDOStatement::fetch()、PDOStatement::fetchAll()等可以检索的位置。
我的目标是能够运行StatementWithCaching::execute()或StatementWithCaching::cache_execute(),并且仍然以相同的方式检索结果(使用StatementWithCaching::fetch()或StatementWithCaching::fetchAll() )。
发布于 2014-12-04 16:56:58
我能够通过扩展PDOStatement::fetch()和PDOStatement::fetchAll()函数来解决这个问题。
namespace trf;
class StatementWithCaching extends \PDOStatement {
protected $db;
protected $cache;
protected $cacheReturn;
protected $cacheQuery;
protected $queryCacheTime;
protected function __construct(&$db) {
$this->db =& $db;
}
function cache_execute( $array = NULL , $cache = FALSE , $cacheTime = 1800 ) {
if( is_a( $cache , 'Memcache' ) ) {
$this->cache = $cache;
$this->queryCacheTime = $cacheTime;
$this->cacheQuery = $this->queryString;
if( $array !== NULL ) {
foreach ($array as $key => $value) {
$this->cacheQuery = str_replace(':' . $key , "'" . addslashes( $value ) . "'", $this->cacheQuery );
}
}
$this->debugData( 'Trying to get data from cache for query: ' . $this->cacheQuery . ' (' . md5( $this->cacheQuery ) . ')' );
$this->cacheQuery = md5( $this->cacheQuery );
try {
$this->cacheReturn = $this->cache->get( $this->cacheQuery );
$this->debugData( 'Reporting return: ' . var_export( $this->cacheReturn , TRUE ) );
}
catch ( \Exception $e ) {
$this->cacheReturn = FALSE;
$this->debugData( $e->getMessage() );
}
if( is_null( $this->cacheReturn ) || $this->cacheReturn == FALSE || is_null( $this->cacheQuery ) || !is_a( $this->cache , 'Memcache' ) ) {
if ($array === null) {
parent::execute();
} else {
parent::execute($array);
}
}
} else {
if ($array === null) {
parent::execute();
} else {
parent::execute($array);
}
}
}
function fetch( $fetchStyle = \PDO::FETCH_BOTH, $cursor_orientation = \PDO::FETCH_ORI_NEXT , $cursor_offset = 0 ) {
if( is_null( $this->cacheReturn ) || $this->cacheReturn == FALSE || is_null( $this->cacheQuery ) || !is_a( $this->cache , 'Memcache' ) ) {
$fullResults = parent::fetchAll();
if( is_a( $this->cache , 'Memcache' ) ) {
$this->debugData( 'Inserting data into cache:' . print_r( $fullResults , TRUE ) );
$this->cache->set($this->cacheQuery , $fullResults , MEMCACHE_COMPRESSED , $cacheTime );
}
return parent::fetch( $fetchStyle , $cursor_orientation = \PDO::FETCH_ORI_NEXT , $cursor_offset = 0 );
}
else {
$this->debugData( 'Returning Cached Results' );
switch ($fetchStyle) {
case \PDO::FETCH_BOTH:
return $this->cacheReturn[$cursor_offset];
break;
case \PDO::FETCH_ASSOC:
$data = $this->cacheReturn[$cursor_offset];
foreach ($data as $key => $value) {
if( is_numeric( $key ) ) {
unset( $data[$key] );
}
}
return $data;
break;
case \PDO::FETCH_LAZY:
$data = $this->cacheReturn[$cursor_offset];
$return = new \stdClass();
foreach ($data as $key => $value) {
if( !is_numeric( $key ) ) {
$return->$key = $value;
}
}
return $return;
break;
case \PDO::FETCH_OBJ:
$data = $this->cacheReturn[$cursor_offset];
$return = new \stdClass();
foreach ($data as $key => $value) {
if( !is_numeric( $key ) ) {
$return->$key = $value;
}
}
return $return;
break;
default:
return $this->cacheReturn[$cursor_offset];
break;
}
}
}
function fetchAll() {
if( is_null( $this->cacheReturn ) || $this->cacheReturn == FALSE || is_null( $this->cacheQuery ) || !is_a( $this->cache , 'Memcache' ) ) {
$fullResults = parent::fetchAll();
if( is_a( $this->cache , 'Memcache' ) ) {
$this->debugData( 'Inserting data into cache: ' . print_r( $fullResults , TRUE ) );
$this->cache->set($this->cacheQuery , $fullResults , MEMCACHE_COMPRESSED , $this->queryCacheTime );
}
return $fullResults;
} else {
$this->debugData( 'Returning Cached Results' );
return $this->cacheReturn;
}
}
private function debugData( $data ) {
if( isset( $_GET['debug'] ) && $_GET['debug'] = DEBUGVAL ) {
print('<pre>');
print_r( $data );
print('</pre>');
}
}
}虽然该解决方案仍然没有处理可以为PDOStatement::fetch()或PDOStatement::fetchAll()设置的所有标志,但可以对其进行进一步扩展。
到目前为止,我已经做了一些测试,结果非常好。
发布于 2014-12-04 16:06:50
我强烈建议您不要将缓存访问逻辑与DB访问逻辑混合使用。换句话说,我不会为了写入缓存而扩展特定于DB的类。毕竟,当您不需要时,为什么尝试将诸如语句、结果集等概念引入一个简单的缓存层。
相反,我将寻找一个更高级别的抽象,可能是一个类,您可以将一个有效的DB连接和一个有效的连接传递到您的缓存层(在您的例子中是Memcache),并让该类编排用于对缓存和DB进行读写的逻辑。
作为一个高级示例(显然,这省略了错误/异常处理等):
class WriteTroughCache {
protected $pdo;
protected $cache;
protected $cache_ttl = 1000;
// not shown variouos other options that might be needed for cache or DB
public function __construct(PDO $pdo, Memcache $cache, $options = array()) {
$this->pdo = $pdo;
$this->cache = $cache;
if (!empty($options)) {
// not shown load options from array into option properties including cache_ttl
}
}
public get($key) {
$result = $this-cache->get($key);
if ($result) {
return $result;
}
// not in cache, get from DB
$value = $this->db_get($key);
if (false === $value) {
// key did not exist in DB
return false;
} else {
// key found in DB
$this->cache->set($key, $value, 0, $this->cache_ttl);
return $value;
}
}
public function set($key, $value) {
// see if key exists
// if so, update cache first
$value = $this->get($key);
if($value) {
$this->cache->set($key, $value, 0 , $this->cache_ttl);
}
return $this->db_set($key, $value);
}
public function db_get($key) {
// not shown perform DB query using PDO object
// return value at key if found or false if not found
}
public function db_set($key, $value) {
// not shown perform DB query using PDO object
// return true or false based on success of insert
}
}https://stackoverflow.com/questions/27296972
复制相似问题