全局或单一的数据库连接?

在PHP中使用singleton代替全局数据库连接有什么好处? 我觉得使用单例而不是全局使代码不必要的复杂。

代码与全球

$conn = new PDO(...); function getSomething() { global $conn; . . . } 

与单身人士代码

 class DB_Instance { private static $db; public static function getDBO() { if (!self::$db) self::$db = new PDO(...); return self::$db; } } function getSomething() { $conn = DB_Instance::getDBO(); . . . } 

如果有更好的初始化数据库连接而不是全局或单例的方法,请提及它并描述它对全局或单例的优点。

我知道这是旧的,但Dr8k的答案几乎在那里。

当你正在考虑写一段代码时,假设它将会改变。 这并不意味着你正在假设在未来的某个时候将会有所改变,而是会有某种forms的改变。

把它作为一个目标减轻未来变革的痛苦:全球化是危险的,因为在一个地方很难pipe理。 如果我想在将来知道该数据库连接上下文,该怎么办? 如果我希望它每5次使用一次就closures并重新打开。 如果我决定为了扩展我的应用程序,我想使用10个连接池? 或可configuration的连接数量?

单件工厂为您提供了灵活性。 我设置它只需要额外的复杂性,而不仅仅是访问相同的连接。 我可以通过简单的方式获得改变连接传递给我的能力。

请注意,我说独立工厂 ,而不是简单的单身 。 单身人士和全球人士之间的差别很小,真实。 正因为如此,没有理由build立一个单一的连接:为什么你会花时间来设置,而不是创build一个普通的全局呢?

一个工厂得到你的是一个为什么要build立连接,另一个位置是决定你将得到什么连接(或连接)。

 class ConnectionFactory { private static $factory; private $db; public static function getFactory() { if (!self::$factory) self::$factory = new ConnectionFactory(...); return self::$factory; } public function getConnection() { if (!$this->db) $this->db = new PDO(...); return $this->db; } } function getSomething() { $conn = ConnectionFactory::getFactory()->getConnection(); . . . } 

然后,在6个月内,当你的应用程序超级出名,并得到dugg和slashdotted,你决定你需要多个连接,所有你需要做的是在getConnection()方法中实现一些池。 或者,如果您决定要实现SQL日志logging的包装器,则可以传递PDO子类。 或者,如果您决定在每次调用时都想要一个新连接,则可以这样做。 它是灵活的,而不是僵化的。

16行代码,包括大括号,这将节省你几个小时和几个小时的重构一些类似的东西。

请注意,我不考虑这个“Feature Creep”,因为我在第一轮中没有执行任何function实现。 这是边界线“未来的蠕变”,但在某种程度上,“为今天的明天编码”这个想法总是一件坏事,而不是为我而动。

我不确定我能否回答你的具体问题,但是想要说明,如果这是一个基于networking的系统,全局/单例连接对象可能不是最好的主意。 DBMS通常被devise为以有效的方式pipe理大量的独特连接。 如果你使用全局连接对象,那么你正在做一些事情:

  1. 强制您的页面按顺序执行所有数据库连接,并消除asynchronous页面加载的任何尝试。

  2. 有可能在数据库元素上打开更长时间的锁,从而降低数据库的整体性能。

  3. 最大限度地提高数据库可以支持的同时连接的总数,并阻止新用户访问资源。

我相信还有其他潜在的后果。 请记住,此方法将尝试维持访问该网站的每个用户的数据库连接。 如果你只有一个或两个用户,没有问题。 如果这是一个公共网站,你想要stream量,那么可伸缩性将成为一个问题。

[编辑]

在较大的缩放情况下,每次点击数据时创build新的连接可能是不好的。 但是,答案并不是创build一个全局连接,并将其重用于一切。 答案是连接池。

通过连接池,可以维护许多不同的连接。 当应用程序需要连接时,将检索池中的第一个可用连接,然后在其作业完成后返回到池中。 如果请求了一个连接但没有任何连接可用,则会发生以下两种情况之一:a)如果未达到允许的最大连接数,则打开一个新连接,或者b)应用程序被迫等待连接变为可用。

注意:在.Net语言中,连接池默认由ADO.Net对象处理(连接string设置所有必需的信息)。

感谢Crad对此发表评论。

单例方法是为了确保只有一个类的实例。 但是,由于人们使用它作为快捷全球化的一种方式,因此被称为懒惰和/或糟糕的编程。

因此,我会忽略全局和Singleton,因为它们都不是真正的OOP。

你正在寻找的是dependency injection

你可以在http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection上查看容易阅读的与dependency injection相关的基于PHP的信息(带有例子)

这两种模式实现相同的净效应,为数据库调用提供一个单一的访问点。

就具体的实现而言,单例有一个小优点,就是在至less有一个其他方法请求它之前,不启动数据库连接。 在我写的大多数应用程序的实践中,这并没有太大区别,但是如果你有一些页面/执行path根本不进行任何数据库调用,这是一个潜在的优点,因为这些页面不会曾经请求连接到数据库。

另一个微小的区别是,全局实现可能无意中在应用程序中对其他variables名称进行了践踏。 你可能不小心声明了另一个全局的$ db引用,尽pipe你可能会意外地覆盖它(比如说,如果你想写if($ db == null)的话,你写了if($ db = null)。单身对象阻止了这一点。

如果你不打算使用持续连接,并且有些情况下不这样做,我发现一个单例在概念上比OOdevise中的全局更可爱。

在一个真正的面向对象的体系结构中,单例比每次创build对象的新实例更有效。

在给定的例子中,我没有理由使用单例。 作为一个经验法则,如果我唯一的担心是允许一个对象的单个实例,如果语言允许的话,我更喜欢使用全局variables

一般来说,我会使用一个单一的数据库连接…你不想每次需要与数据库交互时创build一个新的连接…这可能会损害networking的性能和带宽…为什么创build一个新的,当有一个可用…只是我的2美分…

RWendi

这很简单。 切勿使用全局或单身。