【问题标题】:mysqli or PDO - what are the pros and cons? [closed]mysqli 或 PDO - 有什么优点和缺点? [关闭]
【发布时间】:2010-09-06 00:40:10
【问题描述】:

在我们的位置,我们在使用 mysqli 和 PDO 来处理诸如准备好的语句和事务支持之类的东西之间进行划分。有些项目使用一个,有些项目使用另一个。我们几乎不可能迁移到另一个 RDBMS。

我更喜欢 PDO,因为它允许为准备好的语句使用命名参数,而据我所知 mysqli 不允许。

在我们合并项目以仅使用一种方法时,选择其中一种作为标准是否还有其他优点和缺点?

【问题讨论】:

  • 这个article 将帮助您选择使用哪一个。如果您考虑性能this 可能会帮助您选择。

标签: php mysql pdo mysqli database-abstraction


【解决方案1】:

好吧,您可以与面向对象方面、准备好的语句、它成为标准的事实等争论。但我知道大多数时候,说服某人使用杀手级功能效果更好。就是这样:

使用 PDO 的一个真正好处是您可以获取数据,并自动将其注入对象中。如果您不想使用ORM(因为它只是一个快速脚本)但您喜欢对象映射,那真的很酷:

class Student {

    public $id;
    public $first_name;
    public $last_name

    public function getFullName() {
        return $this->first_name.' '.$this->last_name
    }
}

try 
{
    $dbh = new PDO("mysql:host=$hostname;dbname=school", $username, $password)

    $stmt = $dbh->query("SELECT * FROM students");

    /* MAGIC HAPPENS HERE */

    $stmt->setFetchMode(PDO::FETCH_INTO, new Student);


    foreach($stmt as $student)
    {
        echo $student->getFullName().'<br />';
    } 

    $dbh = null;
}
catch(PDOException $e)
{
    echo $e->getMessage();
}

【讨论】:

  • 上面和$mysqliResult-&gt;fetch_object("student");有区别吗?
  • @e-satis 不,我使用 PHP。公共字段违反了封装,所以AS A BEST PRACTICE 它只是...大声笑 :) Google 不使用公共字段,只使用访问器:google-styleguide.googlecode.com/svn/trunk/…
  • @e-satis:对不起,如果你想控制变量改变时发生的事情,getter 和 setter 是必要的。否则你不能保证你的对象的内部状态(如果你有另一个对象,这尤其是一个问题)。这完全与语言无关。 @OZ_:放轻松。个人批评只会让别人处于守势。
  • @monadic:同意。在处理核心组件或复杂对象等时,封装当然是一个有效的论据,但是作为记录的表示,否则这些记录将是读写关联的。数组,这是可以接受的。此外,当记录在系统中浮动时,它允许更轻松的类型检查。
  • @outis 我希望我在这里不是少数,但我认为不应该根据他们对新开发人员的安全性来判断答案。听起来很刺耳,但这是真的。关于 SO 的答案的目的不仅是提供复制和粘贴代码,而且还提供理解。确保在示例中涵盖每个安全漏洞或模式缺陷并不是回答者的工作,因为让我们面对现实吧,代码被复制到的应用程序本质上不同于使用相同代码的所有其他应用程序。
【解决方案2】:

将应用程序从一个数据库移动到另一个数据库并不常见,但迟早您可能会发现自己正在使用不同的 RDBMS 处理另一个项目。如果您在家中使用 PDO,那么到那时至少需要学习一件事。

除此之外,我发现 PDO API 更直观一些,而且感觉更真正面向对象。 mysqli 感觉它只是一个被客观化的程序 API,如果你明白我的意思的话。简而言之,我发现 PDO 更易于使用,但这当然是主观的。

【讨论】:

    【解决方案3】:

    在我看来,我开始使用 PDO 是因为语句支持更好。我正在使用 ActiveRecord-esque 数据访问层,它更容易实现动态生成的语句。 MySQLi 的参数绑定必须在单个函数/方法调用中完成,所以如果您直到运行时才知道要绑定多少个参数,您将不得不使用call_user_func_array()(我相信这是正确的函数名称) 用于选择。忘记简单的动态结果绑定。

    最重要的是,我喜欢 PDO,因为它是一个非常合理的抽象级别。在您不想编写 SQL 的完全抽象的系统中使用它很容易,但它也可以很容易地使用更优化的纯查询类型的系统,或者混合搭配两者。

    【讨论】:

    • 结果绑定与动态生成的查询是可能的,我们在我们的应用程序中这样做。然而,这是一个巨大的痛苦。
    【解决方案4】:

    PDO 是标准,它是大多数开发人员期望使用的。 mysqli 本质上是针对特定问题的定制解决方案,但它具有其他特定于 DBMS 的库的所有问题。 PDO 是所有辛勤工作和聪明思考的地方。

    【讨论】:

      【解决方案5】:

      还有一点需要牢记:目前(PHP 5.2)PDO 库有缺陷。它充满了奇怪的错误。例如:在变量中存储PDOStatement 之前,变量应该是unset() 以避免大量错误。其中大部分已在 PHP 5.3 中修复,它们将在 2009 年初在 PHP 5.3 中发布,其中可能还有许多其他错误。如果你想要一个稳定的版本,你应该专注于使用 PDO for PHP 6.1,如果你想帮助社区,你应该专注于使用 PDO for PHP 5.3。

      【讨论】:

      • 我认为 PDO 提供的好处值得理解和解决错误。 PHP 本身充满了非常严重的错误,有些我们甚至无法有效地解决,但它提供了许多好处,使我们使用它而不是其他选项。
      • 嗯,奇怪,我从来没有遇到过 PDO 的任何错误。我经常使用它。
      • Mysqli 也有 bug。所有软件都有错误。
      【解决方案6】:

      关于 PDO 的另一个显着(好的)区别是它的 PDO::quote() 方法会自动添加封闭引号,而 mysqli::real_escape_string()(和类似方法)不会:

      PDO::quote() 在输入字符串周围放置引号(如果需要)和 使用引号转义输入字符串中的特殊字符 适合底层驱动程序的样式。

      【讨论】:

        【解决方案7】:

        如果您的站点/Web 应用程序真正成为现实,那么 PDO 将使其更容易扩展.

        PDO Info

        Scaling a Web Application

        【讨论】:

          【解决方案8】:

          在执行速度方面 MySQLi 胜出,但除非你有一个使用 MySQLi 的良好包装器,否则它处理预准备语句的函数很糟糕。

          我的还是有错误,但如果有人想要,here it is

          因此,简而言之,如果您正在寻找速度增益,那么 MySQLi;如果你想要易用性,那么 PDO。

          【讨论】:

          • 在速度方面,你能给出基准吗?
          • Jonathen Robson 在jonathanrobson.me/2010/06/mysqli-vs-pdo-benchmarks 对两者进行了不错的速度比较。总结:inserts - 几乎相等,selects - mysqli 对于未准备好的语句快约 2.5%/对于准备好的语句快约 6.7%。鉴于性能损失非常小,使用 PDO 的功能和灵活性通常超过了性能损失。
          • @Adam 感谢您链接到我的博客!
          • @daemonfire300 这是真的,不需要基准测试。 PDO 包装了 mysqli 库。如果有人能证明 PDO 比 mysqli 快,我可能会大吃一惊。 :-D
          • @jnrbsn 你同意亚当所说的话吗?
          【解决方案9】:

          我个人使用 PDO,但我认为这主要是一个偏好问题。

          PDO 具有一些有助于防止 SQL 注入的功能 (prepared statements),但如果您对 SQL 小心谨慎,您也可以使用 mysqli 来实现。

          移动到另一个数据库并不是使用 PDO 的主要原因。只要不使用“特殊 SQL 功能”,就可以从一个 DB 切换到另一个 DB。但是,一旦您使用例如“SELECT ... LIMIT 1”,您就不能转到“SELECT TOP 1 ...”的 MS-SQL。所以这无论如何都是有问题的。

          【讨论】:

          • MySQLi 已准备好语句。
          【解决方案10】:

          已编辑答案。

          在对这两个 API 有一些经验之后,我会说有 2 个阻塞级别的功能使 mysqli 无法与本机准备语句一起使用。
          他们已经在 2 个出色(但被低估)的答案中提到:

          1. Binding values to arbitrary number of placeholders
          2. Returning data as a mere array

          (在this answer中也提到过)

          由于某种原因,mysqli 两者都失败了。
          现在它对第二个(get_result)有了一些改进,但它只适用于 mysqlnd 安装,这意味着你不能在脚本中依赖这个函数。

          然而直到今天它还没有按值绑定。

          所以,只有一个选择:PDO

          所有其他原因,例如

          • 命名占位符(这种语法糖被高估了)
          • 不同的数据库支持(实际上没有人使用过)
          • 获取到对象(只是无用的语法糖)
          • 速度差异(没有)

          并不重要。

          同时,这两个 API 都缺少一些真正重要的功能,例如

          • 标识符占位符
          • 复杂数据类型的占位符,使动态绑定不那么麻烦
          • 更短的应用程序代码。

          因此,为了满足现实的生活需求,必须基于这些 API 之一创建自己的抽象库,实现手动解析的占位符。在这种情况下,我更喜欢 mysqli,因为它的抽象级别较低。

          【讨论】:

          • 终于有人知道并且不否认生活的事实......
          【解决方案11】:

          在我的benchmark script 中,每种方法都测试了 10000 次,并打印了每种方法的总时间差。您应该根据自己的配置进行此操作,我相信结果会有所不同!

          这是我的结果:

          • "SELECT NULL" -&gt; PGO() 快了约 0.35 秒
          • "SHOW TABLE STATUS" -&gt; mysqli() 快了约 2.3 秒
          • "SELECT * FROM users" -&gt; mysqli() 快​​了约 33 秒

          注意:通过对 mysqli 使用 ->fetch_row(),列名不会添加到数组中,我在 PGO 中没有找到这样做的方法。但是即使我使用 ->fetch_array() ,mysqli 也比 PGO 稍微慢一些,但仍然比 PGO 快(SELECT NULL 除外)。

          【讨论】:

          • 什么是 PGO?而且快了 33 秒?!我觉得这很难相信......
          【解决方案12】:

          PDO 有一点我不喜欢 MySQLi 的,那就是 PDO 能够将结果作为指定类类型的对象返回(例如 $pdo-&gt;fetchObject('MyClass'))。 MySQLi 的fetch_object() 只会返回一个stdClass 对象。

          【讨论】:

          • 其实可以手动指定一个类:“object mysqli_result::fetch_object ([ string $class_name [, array $params ]] )”。仅当您不指定任何内容时才使用 stdClass。
          【解决方案13】:

          要记住一件事。

          Mysqli 不支持 fetch_assoc() 函数,该函数将返回带有表示列名的键的列。当然可以编写自己的函数来做到这一点,它甚至不会很长,但是我真的很难写它(对于非信徒:如果你觉得这很容易,试试吧你自己的一些时间,不要作弊:))

          【讨论】:

          • 很久以前就已经实现了,但是是的,我查看了手册。它适用于准备好的语句吗?我怀疑...
          • 实际上,它有一个奇怪的部分支持。您可以在常规查询中获取数组,但不能在参数化查询中获取:-!
          • 为什么不删除明显错误的答案?
          • @MajidFouladpour - 答案并非明显错误。它只是缺少一些上下文。 Mysqli 确实完全支持关联数组检索。
          猜你喜欢
          • 1970-01-01
          • 2013-06-30
          • 2011-01-03
          • 1970-01-01
          • 2016-02-08
          • 2014-06-26
          • 2011-01-12
          • 1970-01-01
          相关资源
          最近更新 更多