Глобальный или Singleton для подключения к базе данных?

В чем преимущество использования singleton вместо глобального для соединений с базой данных в PHP? Я чувствую, что использование singleton вместо глобального делает код излишне сложным.

Код с глобальным

$conn = new PDO(...);

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

Код с Singleton

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();
    .
    .
    .
}

Если есть лучший способ инициализации соединения с базой данных, отличного от глобального или одиночного, укажите его и опишите преимущества, которые он имеет в глобальном или одиночном режиме.

Ответ 1

Я знаю, что это старо, но ответ Dr8k был почти там.

Когда вы планируете писать фрагмент кода, предположите, что он изменится. Это не означает, что вы принимаете такие изменения, которые он будет поднимать на этом в какой-то момент в будущем, а скорее будут сделаны какие-то изменения.

Сделать цель смягчить боль от внесения изменений в будущем: глобальный опасен, потому что трудно управлять в одном месте. Что делать, если я хочу, чтобы в будущем этот контекст подключения к базе данных был известен? Что, если я хочу, чтобы он закрывался и снова открывался каждый раз, когда он использовался. Что делать, если я решаю, что в интересах масштабирования моего приложения я хочу использовать пул из 10 подключений? Или настраиваемое количество подключений?

A singleton factory дает вам такую ​​гибкость. Я установил его с очень небольшой сложностью и получаю больше, чем просто доступ к тому же соединению; Я получаю возможность изменить, как это соединение передается мне позже, простым способом.

Обратите внимание, что я говорю singleton factory, а не просто singleton. Там очень мало различий между одноэлементным и глобальным, истинным. И из-за этого нет причин иметь одноэлементное соединение: зачем вам тратить время на настройку, когда вы могли бы создать обычный глобальный?

Что получает factory - это почему для получения соединений и отдельное место, чтобы решить, какие соединения (или соединение) вы собираетесь получить.

Пример

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 строк кода, включая фигурные скобки, что позволит сэкономить вам часы, часы и часы рефакторинга, что-то ужасно похожее на линию.

Обратите внимание, что я не рассматриваю этот "Feature Creep", потому что я не выполняю никаких функций в первом раунде. Это пограничная линия "Future Creep", но в какой-то момент идея о том, что "кодирование завтрашнего дня" всегда плохая вещь, не преследует меня.

Ответ 2

Я не уверен, что могу ответить на ваш конкретный вопрос, но хотел предположить, что глобальные/одиночные объекты соединения могут быть не лучшей идеей, если это, если для веб-системы. СУБД, как правило, предназначены для эффективного управления большим количеством уникальных соединений. Если вы используете глобальный объект соединения, вы делаете пару вещей:

  • Задание вам страниц для всей базы данных последовательные соединения и убийства любые попытки на асинхронной странице грузы.

  • Потенциально удерживая открытые блокировки элементов базы данных дольше, чем необходимо, замедляя общее производительность базы данных.

  • Максимальное количество одновременное подключение вашего база данных может поддерживать и блокировать новые пользователи получают доступ к ресурсы.

Я уверен, что есть и другие потенциальные последствия. Помните, что этот метод будет пытаться поддерживать соединение с базой данных для каждого пользователя, обращающегося к сайту. Если у вас есть только один или два пользователя, это не проблема. Если это общедоступный веб-сайт и вам нужен трафик, тогда масштабируемость станет проблемой.

[EDIT]

В более масштабных ситуациях создание новых подключений каждый раз, когда вы попадаете в базу данных, может быть плохим. Однако ответ заключается не в том, чтобы создать глобальное соединение и повторно использовать его для всего. Ответ - объединение пулов.

При объединении пулов поддерживается несколько различных соединений. Когда приложение требуется подключение, первое доступное соединение из пула извлекается, а затем возвращается в пул после выполнения его работы. Если запрашивается соединение и нет ни одного из них, произойдет одно из двух: а) если максимальное количество разрешенных соединений не достигнуто, открывается новое соединение или б) приложение вынуждено ждать, пока соединение станет доступным.

Примечание.. На языках .Net пул соединений обрабатывается объектами ADO.Net по умолчанию (строка подключения задает всю необходимую информацию).

Спасибо Crad за комментарий к этому.

Ответ 3

Метод singleton был создан, чтобы убедиться, что существует только один экземпляр любого класса. Но, поскольку люди используют его как способ ускорить процесс глобализации, он становится известен как ленивое и/или плохое программирование.

Поэтому я бы проигнорировал глобальный и Singleton, поскольку оба они не являются ООП.

То, что вы искали, - это инъекция зависимостей.

Вы можете проверить легко читаемую информацию на основе PHP, связанную с инъекцией зависимостей (с примерами), в http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection

Ответ 4

Оба шаблона имеют одинаковый сетевой эффект, обеспечивая единую точку доступа для вызовов в базе данных.

В терминах конкретной реализации синглтон имеет небольшое преимущество не инициировать соединение с базой данных, пока, по крайней мере, один из его других методов не попросит об этом. На практике в большинстве приложений, которые я написал, это не имеет большого значения, но это потенциальное преимущество, если у вас есть несколько страниц/путей выполнения, которые вообще не производят никаких вызовов базы данных, поскольку эти страницы не будут когда-либо запрашивают соединение с базой данных.

Еще одно незначительное отличие состоит в том, что глобальная реализация может попирать другие имена переменных в приложении непреднамеренно. Маловероятно, что вы когда-нибудь случайно объявите еще одну глобальную ссылку на $db, хотя возможно, что вы можете перезаписать ее случайно (например, вы пишете if ($ db = null), когда вы хотели написать if ($ db == null). Объект singleton предотвращает это.

Ответ 5

Если вы не собираетесь использовать постоянное соединение, и есть случаи, когда вы этого не делаете, я считаю, что синглтон будет концептуально более приемлемым, чем глобальный в дизайне OO.

В настоящей OO-архитектуре одноэлемент более эффективен, чем создание нового экземпляра объекта каждый раз.

Ответ 6

В данном примере я не вижу причин использовать одиночные точки. Как правило, если моя единственная проблема заключается в том, чтобы разрешить один экземпляр объекта, если язык позволяет это, я предпочитаю использовать глобальные переменные

Ответ 7

В общем, я бы использовал singleton для подключения к базе данных... Вы не хотите создавать новое соединение каждый раз, когда вам нужно взаимодействовать с базой данных... Это может повредить производительность и пропускную способность вашей сети... Зачем создавать новый, когда есть один... Только мои 2 цента...

RWendi

Ответ 8

Это довольно просто. Никогда не используйте глобальный синглтон OR.