关于php:Global或Singleton用于数据库连接?

Global or Singleton for database connection?

在PHP中使用singleton而不是global进行数据库连接有什么好处?我觉得使用singleton而不是global会使代码变得不必要的复杂。

使用全局代码

1
2
3
4
5
6
7
8
9
$conn = new PDO(...);

function getSomething()
{
    global $conn;
    .
    .
    .
}

单件编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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的答案就在眼前。

当你考虑写一段代码时,假设它会改变。这并不意味着你要假设未来某个时候它会带来什么样的改变,而是要做出某种形式的改变。

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

单件工厂给你这种灵活性。我用很少的额外复杂性设置它,获得的不仅仅是对同一个连接的访问;我获得了更改该连接稍后以简单方式传递给我的方式的能力。

注意,我说的是单件工厂,而不是简单的单件工厂。一个单身汉和一个全球性的人之间没有什么差别,真的。正因为如此,没有理由建立一个单点连接:当您可以创建一个常规全局时,为什么要花费时间来设置它?

工厂给你带来的是一个为什么要连接的地方,一个独立的点来决定你要连接的地方。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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日志记录的包装器,则可以传递PDO子类。或者,如果您决定每次调用时都需要一个新的连接,您可以这样做。它是灵活的,而不是僵硬的。

包括大括号在内的16行代码,它可以为您节省数小时、数小时和数小时的重构时间,使之与下面的代码非常相似。

请注意,我不认为这是一个"特性蔓延",因为我在第一轮测试中没有进行任何特性实现。这是"未来蔓延"的边界线,但在某种程度上,"今天为明天编码"的想法总是一件坏事,这对我来说并不矛盾。


我不确定是否可以回答您的特定问题,但我想建议,如果是基于Web的系统,全局/单例连接对象可能不是最好的选择。DBMS通常设计为以有效的方式管理大量的唯一连接。如果您使用的是全局连接对象,那么您将执行以下几项操作:

  • 强制页面执行所有数据库连接顺序和杀戮任何异步页尝试荷载。

  • 可能保持打开的锁数据库元素的长度超过必要,整体减速数据库性能。

  • 最大化同时连接您的数据库可以支持和阻塞新用户访问资源。

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

    [编辑]

    在规模较大的情况下,每次访问数据集时都创建新的连接可能很糟糕。然而,答案并不是创建一个全局连接,并将其用于所有内容。答案是连接池。

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

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

    感谢克雷德对此事的评论。


    创建singleton方法是为了确保任何类只有一个实例。但是,因为人们把它作为一种全球化的捷径,它被称为懒惰和/或糟糕的编程。

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

    你要找的是依赖注入。

    您可以在http://components.symfony-project.org/dependency-injection/trunk/book/01-dependency-injection上查看与依赖项注入相关的易于阅读的基于PHP的信息(带示例)。


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

    在具体的实现方面,singleton有一个小的优势,即在至少一个其他方法请求数据库连接之前,不启动它。实际上,在我编写的大多数应用程序中,这并没有什么不同,但是如果您有一些根本不进行任何数据库调用的页面/执行路径,这是一个潜在的优势,因为这些页面永远不会请求与数据库的连接。

    另一个微小的区别是,全局实现可能无意中践踏应用程序中的其他变量名。您不太可能意外地声明另一个全局$db引用,但您可能会意外地覆盖它(例如,当您打算写($db==null)时,如果要写($db==null),则写。singleton对象阻止了这一点。


    在给定的示例中,我看不到使用单例的理由。作为经验法则,如果我唯一关心的是允许对象的单个实例,如果语言允许,我更喜欢使用全局变量


    如果您不打算使用持久连接,并且有不这样做的情况,那么在OO设计中,我发现一个单例在概念上比一个全局的单例更容易接受。

    在真正的OO体系结构中,单实例比每次创建对象的新实例更有效。


    一般来说,我会使用一个singleton进行数据库连接…您不希望每次需要与数据库交互时都创建新连接…这可能会损害您网络的性能和带宽…为什么要创建一个新的,当有一个可用的时候…只是我的2美分…

    雷文迪


    作为建议,singleton和global都是有效的,可以在同一个系统、项目、插件、产品等中加入。在我的例子中,我为网络制作数字产品(插件)。

    我在主班只使用单例,原则上使用它。我几乎不使用它,因为我知道主类不会再次实例化它。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <?php // file0.php

    final class Main_Class
    {
        private static $instance;
        private $time;

        private final function __construct()
        {
            $this->time = 0;
        }
        public final static function getInstance() : self
        {
            if (self::$instance instanceof self) {
                return self::$instance;
            }

            return self::$instance = new self();
        }
        public final function __clone()
        {
            throw new LogicException("Cloning timer is prohibited");
        }
        public final function __sleep()
        {
            throw new LogicException("Serializing timer is prohibited");
        }
        public final function __wakeup()
        {
            throw new LogicException("UnSerializing timer is prohibited");
        }
    }

    几乎所有二级类的全局使用,例如:

    1
    2
    3
    <?php // file1.php
    global $YUZO;
    $YUZO = new YUZO; // YUZO is name class

    在运行时,我可以使用Global在同一个实例中调用它们的方法和属性,因为我不需要我的主产品类的另一个实例。

    1
    2
    3
    4
    <?php // file2.php
    global $YUZO;
    $YUZO->method1()->run();
    $YUZO->method2( 'parameter' )->html()->print();

    我得到的全局是使用相同的实例,能够使产品工作,因为我不需要一个工厂为同一类的实例,通常实例工厂是为大型系统或非常罕见的目的。

    In conclusion:,如果你已经很好地理解了这是反模式单件,并且了解了全局,你可以使用这两个选项中的一个或者混合它们,但是如果我建议不要滥用它们,因为有许多程序员非常例外,并且忠实于编程OOP,那么就将它用于主要和次要类,而这些类是你经常与我一起使用的。n执行时间。(它为您节省了大量CPU)。???


    这很简单。不要使用全局或单例。