2009-12-06 36 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

相關問題