Php 如何在准备好的语句中使用memcached?
缓存常规SQL查询非常简单Php 如何在准备好的语句中使用memcached?,php,memcached,prepared-statement,Php,Memcached,Prepared Statement,缓存常规SQL查询非常简单 public function query($sql) { if( $result = cache::get(sha1($sql)) ) { return $result; } $result = $this->connection->query($sql); cache::set(sha1($sql), $result); return $result; } 但是,既然在语句已经准备好并绑定数
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();
我觉得这是一个由两部分组成的答案:首先,语句被缓存在每页内存中(就像$this->statements[]),因为数据库资源ID不会持续很长时间,不能存储在文件或任何东西中
其次,在执行语句()之前,我们通过散列用于创建语句的sql(easy with
PDOStatement::queryString
)和给定参数的散列,在memcached/filecache中查找结果。问题是在语句对象中查找参数
当然,这只是一个想法,可能还有更好的解决方案。那么,您必须将每个参数的值添加到缓存密钥中。大概是这样的:
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);
}
}
您必须匹配计划使用的每个PDO语句方法。PDO::FETCH_-INTO实现起来也会有点痛苦。我的建议是:专注于自己的使用。也许您甚至不必在dbh级别实现缓存,相反,您可以只在缓存重要的地方添加缓存功能
无论如何,请记住,您编写的代码越多,需要维护的代码就越多,您在应用程序中引入错误的可能性就越大。因此,在对缓存层进行成本/收益分析时要小心,因为缓存层可能会过于聪明,这对其自身有利:)开始得不错,但是对于大多数先创建语句(从sql开始),然后再添加参数(而不是同时添加这两个参数)的实例,情况又如何呢我认为不能从语句中获取原始SQL,因此必须制作一个语句包装器,将原始SQL和准备好的语句存储在一起。根据我的经验,我发现很难扩展或包装MySQLi,因为参数绑定和结果获取的方式,以及大多数参数都是通过引用传递的,这就是为什么我现在更喜欢使用PDO。哦,我没有注意到这实际上是PDO的方法签名。我有自己的stmt()包装器,所以一眼就认不出它们。
PDOStatement::queryString
包含准备好的SQL,因此可能有一些方法可以使用它。很好,因为您可以扩展PDO和MySQLi语句,我希望您可以重写execute()
和bind*()
方法执行检查,然后调用父项::*()
。我试试这个。