我正在尝试使用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()
)。
答案 0 :(得分:1)
我强烈建议您不要将缓存访问逻辑与数据库访问逻辑混合使用。换句话说,我不会尝试扩展特定于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
}
}
答案 1 :(得分:0)
我能够通过扩展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()
设置的所有标志,但可以进一步扩展该标志。
到目前为止,我已经进行了一些非常好的测试。