【问题标题】:Using a mySQL Prepared Statement in Multiple Class Instances在多个类实例中使用 mySQL 准备语句
【发布时间】:2013-07-29 12:15:51
【问题描述】:

我正在尝试了解如何最好地利用 mysqli 准备好的语句,而且我对面向对象的 PHP 也很陌生。

我知道准备一个语句然后多次执行它比简单地重复相同的查询要高效得多。

下面的类通过主键获取声音对象。如果我需要在同一个脚本中拥有这个类的多个实例,我会从准备好的语句中获得好处吗?

这是否适合存储过程?

class sound {
    public $id;
    public $name;
    public $musickey;

    public function __construct($id) {
        $this->id = $id;
        $sqli = new mysqli();
        if($stmt = $con->prepare("SELECT name, musickey FROM sounds WHERE id = ?")) {
        $stmt->bind_param("i", $this->id);
        $stmt->execute();
        $stmt->bind_result($name, $musickey);
}

我希望我的问题不是重复的。我一直在尝试找到有关此主题的内容,但有时提出正确的问题可能与找到答案一样困难。

【问题讨论】:

    标签: php oop mysqli prepared-statement


    【解决方案1】:

    我知道准备一个语句然后多次执行它比简单地重复相同的查询要高效得多。

    正确。因为服务器端准备好的语句(mysqli 使用的)仅在后续执行时将绑定的参数发送到数据库,而不是整个查询。此外,数据库服务器不必重新解析查询,但可以重用准备好的查询。因此,这可以对检索数据产生影响。所以理论上,这样更有效。

    http://php.net/manual/en/mysqli.quickstart.prepared-statements.php

    在实践中,不要期望有那么大的差异。这当然取决于您打算调用的查询的数量和复杂性以产生重大影响。如有疑问,请进行基准测试。

    它还具有protecting you from SQL Injection 的额外好处。

    下面的类通过主键获取声音对象。如果我需要在同一个脚本中拥有这个类的多个实例,我会从准备好的语句中获得好处吗?

    没有。因为 mysqli 会在您每次创建新实例以准备该语句时向服务器发起查询。除了执行调用。所以你什么也赢不了。使用类似的东西会更直接

    $query = sprintf('SELECT name, musickey FROM sounds WHERE id = %d', $id);
    

    如果您真的希望每个 ID 有一个实例,则将其作为一个整体查询执行。

    如果您想使用准备好的语句执行此操作,您只需要一个准备一次但可以将 ID 传递给多次的实例。

    这是否适合存储过程?

    如果您将应用程序逻辑放入存储过程中,您的应用程序的可移植性就会降低。如果您想在某一时刻更改数据库系统,则需要重新创建存储过程。这取决于您做出明智的选择。如果您不需要更改数据库系统,那么它可能是可行的。我更喜欢将逻辑保留在应用程序中。

    我对面向对象的 PHP 也很陌生。

    One aspect of OOP is about encapsulating and hiding information(和复杂性)来自客户。因此,拥有公共财产并不是最好的主意。此外,doing work in the constructor is not what the constructor is for. 构造函数只应将您的对象置于有效状态。并且由于准备会执行查询,因此您希望将其推迟到需要时。

    说了这么多,考虑

    interface FindById
    {
        public function findById($id);
    }
    
    class SoundFinder implements FindById
    {
        private $mysqli;
        private $statement;
        private $query = "SELECT name, musickey FROM sounds WHERE id = ?";
    
        public function __construct(mysqli $mysqli) 
        {
            $this->mysqli = $mysqli;
        }
    
        private function prepare()
        {
            $this->statement = $mysqli->prepare($this->query)
        }
    
        public function findById($id)
        {
            if (!$this->statement) {
                $this->prepare();
            }
            $this->statement->bind_param("i", $this->id);
            $this->statement->execute();
            $this->statement->bind_result($name, $musickey);
            $this->statement->free_result();
            return array($name, $musickey);
        }
    }
    

    那么你可以这样使用它:

    $connection = new mysqli(/* your connection data */);
    $soundFnder = new SoundFinder($connection);
    $sound42 = $soundFinder->findById(42);
    $sound314 = $soundFinder->findById(314);
    

    【讨论】:

    • 我知道我错过了一些非常基本的东西。我没有想过只创建然后重用该类的一个实例。很好的解释。谢谢。
    • 我不是要调出死线程,而是在准备函数中,不应该是 $this->mysqli->prepare() 吗?如果我确定我会编辑帖子
    【解决方案2】:

    比简单地重复相同的查询要高效得多。

    你理解错了。
    不知道是谁告诉你的,但根本没有“更多”。
    差异几乎不明显,而且通常不值得一团糟。特别是在这种简单的主键查找的情况下。

    我会从准备好的陈述中受益吗?

    我怀疑。

    如果这样的地方曾经成为瓶颈(请注意,这是唯一需要进行任何优化的理由),最好在一个查询中选择所有数据>.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多