Php 如何在准备好的语句中使用memcached?

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; } 但是,既然在语句已经准备好并绑定数

缓存常规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;
}
但是,既然在语句已经准备好并绑定数据之前,您不知道查询将是什么,那么如何使用准备好的语句缓存查询呢

$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*()
方法执行检查,然后调用
父项::*()
。我试试这个。