2009-12-06 101 views
2

缓存常规SQL查询非常简单。你如何使用准备好的语句使用memcached?

public function query($sql) { 

    if($result = cache::get(sha1($sql))) { 
     return $result; 
    } 

    $result = $this->connection->query($sql); 
    cache::set(sha1($sql), $result); 
    return $result; 
} 

但你如何缓存预处理语句的查询,因为你不知道查询会有什么后声明已经准备,然后将数据绑定到?

$sth = $dbh->prepare('SELECT * FROM table WHERE id = ?'); 

...later... 

$sth->bindParam(1, $id); 
$sth->execute(); 

给我的感觉,这是一个两部分的答案:首先,陈述在每页内存中缓存(像$这个 - >语句[]数组),因为数据库资源标识赢得时间不长,不能存储在文件或任何东西。其次,在执行语句()之前,我们通过散列用于创建语句的sql(易于使用PDOStatement::queryString)以及给出的参数的散列来查看memcached/filecache中的结果。麻烦的是在声明对象中找到参数。

当然,这只是一个想法,可能有更好的解决方案。

回答

1

那么,您必须将每个参数的值添加到缓存键中。类似这样的:

public function stmt($sql, $params) { 

    $cache_key = sha1($sql . serialize($params)); 

    if($result = cache::get($cache_key)) { 
     return $result; 
    } 

    $sth = $this->connection->prepare($sql); 

    $i = 0; 
    foreach ($params as &$param) 
    { 
     $sth->bindParam(++$i, $param); 
     $sth->execute(); 
    } 
    unset($param) 

    // fetch all the rows into $result 

    cache::set($cache_key, $result); 
    return $result; 
} 

$obj->stmt('SELECT * FROM table WHERE id = ?', array(&$id)); 

我会让它适应您的需求。你必须获取行并将它们存储在一个数组中。


这里是你不得不使用的那种包装的:

class stmt 
{ 
    protected $sth, $sql, $cache, $params = array(); 

    public function __construct($dbh, $sql) 
    { 
     $this->sth = $dbh->prepare($sql); 
     $this->sql = $sql; 
    } 

    public function bindParam($param, &$var) 
    { 
     $this->params[$param] =& $var; 
     return $this->sth->bindParam($param, $var); 

     // or, if you want to support all the args 
     $args = func_get_args(); 
     $args[1] =& $var; 

     return call_user_func_array(array($this->sth, 'bindParam'), $args); 
    } 

    public function execute(array $params = null) 
    { 
     $str = serialize(isset($params) ? $params : $this->params); 
     $cache_key = sha1($this->sql . $str); 

     // insert cache logic here... 

     if (isset($params)) 
     { 
      $this->stmt->execute($params); 
     } 
     else 
     { 
      $this->stmt->execute(); 
     } 

     $this->cache = $this->stmt->fetchAll(); 

     // save cache here 
    } 

    public function fetch() 
    { 
     return array_shift($this->cache); 
    } 
} 

你不得不与您打算使用的每PDOStatement对象的方法。 PDO :: FETCH_INTO也会带来一些痛苦。我的建议:关注你自己的用法。也许你甚至不需要在dbh级别实现缓存,而是只能在缓存功能的位置添加缓存功能。

无论如何,请记住,您编写的代码越多,您需要维护的代码就越多,并且越有可能在应用程序中引入错误。所以,要小心缓存层的成本/效益分析,它会尝试过于聪明,因为它本身不错:)

+0

好的开始,但是大多数情况下,首先创建语句(从sql),然后再创建参数被添加(而不是同时)? – Xeoncross 2009-12-06 20:18:08

+0

在这种情况下,你几乎搞砸了。 :)我不认为你可以从语句中获得原始SQL,因此你必须创建一个声明包装器,将原始SQL和准备好的声明一起存储。根据我的经验,我发现扩展或包装MySQLi比较困难,因为参数绑定和结果被提取的方式很多,并且因为大多数参数都是通过引用传递的,所以我现在更喜欢使用PDO。 – 2009-12-06 20:24:11

+0

哦,我没有注意到它实际上是PDO的方法签名。我有我自己的stmt()包装,所以我一见钟情就不认识他们。 – 2009-12-06 20:28:58

相关问题