在多个类实例中使用mySQL Prepared语句

时间:2013-07-29 12:15:51

标签: php oop mysqli prepared-statement

我正在努力了解如何最好地利用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);
}

我希望我的问题不重复。我一直试图找到关于这个主题的东西,但有时形成正确的问题可能与找到答案一样困难。

2 个答案:

答案 0 :(得分:2)

  

据我所知,准备一个语句然后多次执行它比简单地重复相同的查询更有效。

正确。因为服务器端预处理语句(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);

答案 1 :(得分:-1)

  

比简单地重复相同的查询更有效率。

你理解错了。
Dunno告诉过你,但根本没有“更多” 这种差异几乎不可察觉,往往不值得一塌糊涂。特别是在这种直接主键查找的情况下。

  

我会从准备好的声明中获益吗?

我对此表示怀疑。

如果这样的地方成为瓶颈(唯一的理由打扰任何优化,请注意),最好选择一个查询中的所有数据