class DataBase

 
0
 
PHP
ava
Zorak | 17.03.2013, 20:52
Здраствуйте дамы и господа. У меня вопрос чисто теоретический.... пока
Написал класс, который отвечает за работу с базой данных на страницах моего сайта.
Вот некоторые методы класса:
1. __construct() - обеспечивает соединение с базой данных
2. __destruct() - обеспечивает закрытие существующего соеднения с базой данных
3. методы select(), insert(), update(), delete() - тут и так все понятно.

За иронией судьбы (так сказать)  я подключаю этот класс на каждой странице и в некоторых классах, где он мне требуется. Естессно при создании обьекта класса происходит подключение к базе данных, далее браузеру передается сгенерированная страница по коду, ну и в конце уничтожается обьект класса, в следствии чего и разрывается соединение с базой данных. И таким макаром происходит на каждой странице.
Проблема в том, что я некоторым чутьем чуствую что гдето промахнулся, а в друг потом напишу несколько страниц, где будут пересекатся разные классы и обьект класса DataBase создастся два раза а того более хуже больше чем два...
И так, вопроса два:
1. Чем это чревато?
2. как это исправить ? (хотябы куда и под каким углом смотреть).

Не хочется потом переписывать фиг знает что и сколько...

Спасибо!
Comments (29)
ava
Gold Dragon | 18.03.2013, 07:39 #
ну  для класса базы данных тебе нужно воспользоваться шаблоном проектирования Singleton. Т.е. Объект создаётся всего один раз.. Вот примерная структура


class GDDatabase
{
    /** @var string - хост */
    private $_db_host;

    /** @var string - пользователь */
    private $_db_user;

    /** @var string - пароль */
    private $_db_password;

    /** @var string - имя БД */
    private $_db_name;

    /** @var string - порт */
    private $_db_port;

    /** @var string - сокет */
    private $_db_socket;

    /** @var int - флаг отладки */
    private $_db_debug;

    /** @var int - флаг кэширования */
    private $_db_caching;

    /** @var string - префикс для таблиц */
    private $_db_prefix;

    /** @var string - путь до файлов кэширования */
    private $_db_cache_dir;

    /** @var int - время кэширования */
    private $_db_cache_time;

    /** @var null|object - интерфейс */
    protected static $_resource = null;

    /** @var \mysqli - MySQLi object */
    protected $db_resource;

    /** @var \mysqli_stmt - MySQLi_STMT object */
    protected $stmp;

    /***************************************************************************
     * Magic methods
    /***************************************************************************/

    /**
     * Конструктор
     * Защищаем от создания через new
     */
    private function __construct()
    {
        // Сохранение основных настроек
        // т.е. достаём из конфигурации настройки для подключения к БД и сохраняем их

        $this->_db_host = JCore::getCfg('host');

        $this->_db_user = JCore::getCfg('user');

        $this->_db_password = JCore::getCfg('password');

        $this->_db_name = JCore::getCfg('db');

        $this->_db_port = JCore::getCfg('port');

        $this->_db_socket = JCore::getCfg('socket');

        $this->_db_debug = JCore::getCfg('debug');

        $this->_db_caching = JCore::getCfg('caching');

        $this->_db_prefix = JCore::getCfg('dbprefix');

        $this->_db_cache_dir = JCore::getCfg('cachepath');

        $this->_db_cache_time = JCore::getCfg('cachetime');

        // Проверка существует ли вообще функция подключения
        if (!function_exists('mysqli_connect')) {
            throw new Exception(_EXCEP_MYSQLI_MODULE_NOT);
        }

        // Временно отключаем вывод ошибок
        $_error = error_reporting();
        error_reporting(0);

        // Создаём объект базы
        $this->db_resource = new mysqli(
            $this->_db_host,
            $this->_db_user,
            $this->_db_password,
            $this->_db_name,
            $this->_db_port,
            $this->_db_socket);

        if ($this->db_resource->connect_error) {
            throw new Exception(_EXCEP_ERROR_CONNECT_DB);
        }

        // Возвращаем состояние вывода ошибок
        error_reporting($_error);

        // Устанавливаем кодировку
        if (!$this->db_resource->set_charset('utf8')) {
            throw new Exception(sprintf(_EXCEP_ERROR_LOADING_CHARACTER_SET, $this->db_resource->character_set_name()));
        }

        // записываем логи запросов
        if ($this->_db_debug) {
            $this->db_resource->query('set profiling=1');
            $this->db_resource->query('set profiling_history_size=100');
        }
    }

    /**
     * Защищаем от создания через клонирование
     */
    private function __clone()
    {
    }

    /**
     * Защищаем от создание через unserialize
     */
    private function __wakeup()
    {
    }

    /**
     * @static Подключение класса
     *
     * @return object
     */
    public static function Init()
    {
        if (!is_object(self::$_resource)) {
            $class_name = __CLASS__;
            self::$_resource = new $class_name;
        }

        return self::$_resource;
    }

}


использовать можно так

$_db = GDDatabase::Init();

Т.е. объект создаётся один раз, а все остальные подключения просто возвращают то что уже создано

ну  и дальше твои методы


$_db->select .....
$_db->insert .....


или  сразу

GDDatabase::Init()->select ....
GDDatabase::Init()->insert ....




ps
если вдруг что, то вот мой класс-обёртка  smile 
https://code.google.com/p/gddatabase/
ava
Zorak | 18.03.2013, 09:12 #
Такс, основную суть я понял, спасибо тебе огромнейшое, подарил мне как минимум одну или две бессонных ночей)... ушол разбиратся, если что буду писать.
ava
ksnk | 18.03.2013, 09:39 #
Zorak, Мне отчего-то нравятся функции драйвера базы данных, которые возвращают не рессурсы, а данные.
Интерфейс получается, кроме служебных конструкторов-деструкторов еще и 
  • insert - возвращает количество вставленных строк
  • update - количество измененных строк.
  • select - возвращает массив массивов строк
  • selectCell - одно значение
  • selectCol - столбец - массив значений
  • selectRow - строка
Так получится менее затратно переходить на новый драйвер базы данных. с mysql, например на mysqli.
ava
Gold Dragon | 18.03.2013, 10:08 #
ksnk, однозначно ! А иначе для чего нужна обёртка  smile 

а ещё вот какие:
  • selectAll - получить все данные указав только таблицу
  • getCacheSql - ну это запрос к базе, но при использовании кэширования
  • getQueryInfo - получение дополнительной информации о запросе (количество строк, затронутых последним запросом, ID предыдущей
операцией INSERT, число строк в результате запроса, число полей в заданном выражении, ошибка последнего запроса и т.п.)

соответственно ещё 
  • getError
  • getErrno

ЗЫ
у меня в классе это всё реализовано. Да и используются подготовленные данные, так что нет смысла что-то экранировать и бояться  smile 
ava
Sanchezzz | 18.03.2013, 11:52 #
А я сижу делаю обертку вокруг PDO для своего микро фреймворка
Поделюсь с задумкой а может для кого то идеями.

Есть класс db - это коллекция синглитон адаптеров, которые работают с разными СУБД, NOSQL
С какой базой данной работать определяется конфигом в виде массива.

db::make() - загрузка настройки по умолчанию, db::make('mongo') загрузка указанной настройки.

dbPdo Обертка над PDO
dbMongo Обердка над монго.

Работа с БД происходит точно также как и с обычным PDO за  исключением того что все методы можно вызвать цепочкой, меня жутко бесило это  в обычном PDO что это нельзя было это сделать.
$db = db::make();
$db->cache($duration)->prepare ... работа с кэшем, кэш также определяется в конфиге к БД, как и профайлер, логер.

$db->prepare($sql)->execute(array(':id',1))
->fetchAll()  // результат все
->fetch()     // первоя строка + курсор в цикде.
->fetchCulumn($column_name) // результат указанный столбец
->asModel()  // результат в виде AR модели или ее подобие (допиливаю последнее время)

$db->prepare($sql)
->bindValue
->bindParam
->execute()
->fetchAll

Эмуляция плейхостов нужна для логера и дебагера.

$db->saveModel($this_class); // сохранить указанную AR модель под текущую БД. Под каждую БД приходится писать свои костыли что бы сохранить модель.
// Модель нечего нечего не знает о базе.
// Модель спроектирована уже с необходимой структурой и связями.

$db->query($prepare,$execute,$debug=false); // результат INSERT UPADETE SELECT DELETE
$db->insert($table, $arraySet);
$db->update($table, $arraySet);

ava
Fortop | 18.03.2013, 14:48 #
Цитата (Gold Dragon @  18.3.2013,  07:39 findReferencedText)
ну  для класса базы данных тебе нужно воспользоваться шаблоном проектирования Singleton.

Разве?

А я думал что он нужен для подключения/адаптера, и то не всегда smile
ava
Gold Dragon | 18.03.2013, 14:52 #
Цитата (Fortop @  18.3.2013,  15:48 findReferencedText)
А я думал что он нужен для подключения/адаптера, и то не всегда 
а по понятнее?
ava
Fortop | 18.03.2013, 16:42 #
По понятнее?

Избежать множества запросов синглтоном нельзя.
Но избежать множества открытий/закрытий соединения - можно.

Вся привычка делать класс работы с БД синглтоном базируется как раз на этой логике.
А раз так... то делаем синглтоном класс подключения/адаптера и используем его в своих обертках.


// one.php
$db = new SuperWrapper(Connection::getInstance());
$db->query(......)

// two.php
$somewhereElse = new DuperWrapper(Connection::getInstance());


ava
baldina | 18.03.2013, 17:32 #
Цитата (Fortop @  18.3.2013,  16:42 findReferencedText)
А раз так... то делаем синглтоном класс подключения/адаптера и используем его в своих обертках.

и в чем разница/выигрыш? 
ava
Fortop | 18.03.2013, 17:45 #
Цитата (baldina @  18.3.2013,  17:32 findReferencedText)
и в чем разница/выигрыш? 

Разница в архитектуре.

А вот выигрыш - вопрос спорный smile
Несколько более гибкое приложение, при условии развитого DBAL
ava
baldina | 18.03.2013, 17:51 #
Цитата (Fortop @  18.3.2013,  17:45 findReferencedText)
Несколько более гибкое приложение

а если потребуется еще одно соединение?
ava
Fortop | 18.03.2013, 22:14 #
Цитата (baldina @  18.3.2013,  17:51 findReferencedText)
а если потребуется еще одно соединение?

Модифицируем до пула.
Или низводим с уровня синглтона соединения вообще и используем Registry для их хранения
ava
baldina | 18.03.2013, 23:11 #
Цитата (Fortop @  18.3.2013,  22:14 findReferencedText)
Модифицируем до пула.


массив-синглтон? массив синглтонов? масло масляное
Цитата (Fortop @  18.3.2013,  22:14 findReferencedText)
используем Registry

который тоже синглтон?

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

 smile 
ava
Fortop | 19.03.2013, 02:11 #
Цитата (baldina @  18.3.2013,  23:11 findReferencedText)
массив-синглтон? массив синглтонов? масло масляное

А кроме личных предпочтений к ношению розовых бикини аргументация будет?  smile 

Цитата (baldina @  18.3.2013,  23:11 findReferencedText)
потом обнаруживаются проблемы с последовательностью их инициализации

С последовательностью инициализации кого?
Соединений с БД?  smile 
ava
ksnk | 19.03.2013, 08:25 #
Вообще-то все драйвера и обертки нужны для того, чтобы писать красиво  smile То есть сначала нужно придумать как это будет написано, а потом уже реализовать, если это возможно.
Fortop предлагает писать так:

// one.php
$db = new SuperWrapper(Connection::getInstance());
$db->query(......)
// two.php
$somewhereElse = new DuperWrapper(Connection::getInstance());


А baldina как предпочитает видеть этот кусок?
ava
baldina | 19.03.2013, 10:16 #
ksnk, дело вовсе не в драйверах и не обертках. это вопрос не вкуса, а архитектуры.
важно не как оно выглядит (это тоже важно, но во вторую очередь), а как структурно устроено.
я сказал, что singleton это плохо масштабируемое решение, поэтому должен применяться как лекарственный яд - строго по назначению малыми дозами.

Цитата (Fortop @  19.3.2013,  02:11 findReferencedText)
Цитата(baldina @  18.3.2013,  23:11 )

потом обнаруживаются проблемы с последовательностью их инициализации

С последовательностью инициализации кого?

к несчастью к php это в малой степени относится (к несчастью - потому что провоцирует на применение). в php проблема возникает лишь в случае зависимости объектов, при которой требуется определенный порядок инициализации. в случае решения на основе синглтонов некому этот порядок обеспечить и контролировать.

я вижу решение в использовании единственного "как бы" синглтона - объекта типа Application, который и порядок инициализации обеспечивает, и предоставляет доступ к объектам, глобальным в контексте приложения, и сам является масштабируемым.
ava
Fortop | 19.03.2013, 13:19 #
Цитата (baldina @  19.3.2013,  10:16 findReferencedText)
я вижу решение в использовании единственного "как бы" синглтона - объекта типа Application, который и порядок инициализации обеспечивает, и предоставляет доступ к объектам, глобальным в контексте приложения, и сам является масштабируемым.


Наводящий вопрос.

Каким образом оно масштабируется?

ava
baldina | 19.03.2013, 13:36 #
Цитата (Fortop @  19.3.2013,  13:19 findReferencedText)
Каким образом оно масштабируется?

добавлением метода в класс Application
само приложение может быть масштабировано созданием нескольких объектов Application (хотя к задачам веб это думаю не относится))
ava
Fortop | 19.03.2013, 17:01 #
Цитата (baldina @  19.3.2013,  13:36 findReferencedText)
само приложение может быть масштабировано созданием нескольких объектов Application

Итого? получаем кучку тех же самых синглтонов?  smile 
В чем тут отличие от масштабирования приложений на пхп?
И как порядок инициализации может мешать подобному масштабированию?  smile
ava
ksnk | 19.03.2013, 17:33 #
Цитата (Fortop @  19.3.2013,  13:19 findReferencedText)
Увы, не для "красиво".
Красота не бывает абстрактной. Она обязана приносить пользу  smile 

В программировании "красивая" польза будет
-- поддержка проекта, в дальнейшем, чужими людьми. Решается достаточной документацией и комментариями.
-- возможность дальнейшего роста проекта, добавление новых возможностей, фич. Решается проектированием и выбором масштабируемых решений.
-- повторная используемость кода. Это когда код (классы, функции и кусочки кода) в меру тупо и без особых изменений могут быть скопированы в другой, новый проект и там заработают правильно и достаточно эффективно.

Вот эта третья красивость тянет за собой минимизацию зависимостей от окружения. Слова, которые определяются в других классах-функциях, должны по возможности исключаться, или быть изолированы в отдельном месте класса - функции... Так чтобы это не противоречило остальным факторам "красивого кода".
ava
baldina | 19.03.2013, 18:30 #
Цитата (Fortop @  19.3.2013,  17:01 findReferencedText)
Цитата(baldina @  19.3.2013,  13:36 )

само приложение может быть масштабировано созданием нескольких объектов Application

Итого? получаем кучку тех же самых синглтонов?

они уже не синглтоны, в том то и дело smile



В чем тут отличие от масштабирования приложений на пхп?

не php, а web. и если бы были, уже кто-нить придумал бы соотв. архитектурное решение
пример: приложение как расчетный модуль. если приложение организовано через единственный объект, можно завести еще один объект и параллельно решать две однотипные задачи. а если приложение содержит ряд синглтонов (или просто глобальных переменных)?

Цитата (Fortop @  19.3.2013,  17:01 findReferencedText)
И как порядок инициализации может мешать подобному масштабированию?   

порядок инициализации может мешать масштабированию, если он требуется, но никто им не управляет
ava
Fortop | 19.03.2013, 18:58 #
Цитата (baldina @  19.3.2013,  18:30 findReferencedText)
приложение как расчетный модуль. если приложение организовано через единственный объект, можно завести еще один объект и параллельно решать две однотипные задачи. а если приложение содержит ряд синглтонов (или просто глобальных переменных)? 

В php нет тредов.
Поэтому завести еще один объект и решать параллельно можно только вместе с новым процессом.

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

Цитата (baldina @  19.3.2013,  18:30 findReferencedText)
порядок инициализации может мешать масштабированию, если он требуется, но никто им не управляет 

Это не относится к работе синглтонов, пула и т.п. в рамках скрипта.

Т.е. либо порядок инициализации никак не влияет на работу приложения и соответственно свободно масштабируем.
Или если порядок инициализации мешает масштабированию, то в случае с php скорее всего ваш скрипт нерабочий даже в единственном числе (хотя и есть нюансы, например, связанные с эксклюзивным доступом к каким-либо ресурсам системы)
ava
Gold Dragon | 19.03.2013, 19:34 #
Fortop, что в твоём понимании масштабирование..? Просто читаю и чем больше, тем хуже начинаю понимать  smile 

Цитата (Fortop @  19.3.2013,  19:58 findReferencedText)
хотя и есть нюансы, например, связанные с эксклюзивным доступом к каким-либо ресурсам системы
а доступ к базе данных к этому не относится?
ava
baldina | 19.03.2013, 19:37 #
Цитата (Fortop @  19.3.2013,  18:58 findReferencedText)
В php нет тредов.

во-первых, параллельно можно работать кооперативно. во-вторых, речь шла об архитектуре вообще

Цитата (Fortop @  19.3.2013,  18:58 findReferencedText)
в случае с php скорее всего ваш скрипт нерабочий даже в единственном числе

да. причем не рабочим он может быть далеко не на первый взгляд, и предстоит веселая отладка.
ava
baldina | 19.03.2013, 19:58 #
итог: создание экземпляра объекта db и т.п. и его предоставление приложению - дело не библиотеки (доступа к бд), а приложения. т.к. библиотека не знает в рамках какой архитектуры она будет работать, а предоставление синглтона на уровне библиотеки (тем более без возможности альтернативного создания объекта) как минимум стимулирует неправильное использование в рамках конкретной архитектуры.

(для простых приложений возможность использования контекста по умолчанию удобно, как это устроено в php_mysql. в процедурном стиле mysqli от этого отказались, т.к. ножик острый)
ava
Fortop | 19.03.2013, 23:13 #
Цитата (Gold Dragon @  19.3.2013,  19:34 findReferencedText)
Fortop, что в твоём понимании масштабирование..? Просто читаю и чем больше, тем хуже начинаю понимать   

В смысле?
Масштабирование это увеличение используемых для решения задачи ресурсов.

Фокус в том, что для многих языков оно доступно через многозадачность в потоках.
Но php не поддерживает подобное решение (и это во многом его плюс).
Т.е. любое масштабирование задачи на php сводится к запуску дополнительных копий скрипта (на этой машине или многих других машинах - не суть важно).
Поэтому у задач на пхп обычно нет тех проблем, на которые пытался ссылаться baldina.

Т.е. конечный php-скрипт с его пространством имен и есть тот самый Application
В многих других языках все не так просто.

Цитата (Gold Dragon @  19.3.2013,  19:34 findReferencedText)
а доступ к базе данных к этому не относится?

Нет, обычно не относится, поскольку база поддерживает множество подключений.
ava
Gold Dragon | 19.03.2013, 23:36 #
Цитата (Fortop @  20.3.2013,  00:13 findReferencedText)
Масштабирование это увеличение используемых для решения задачи ресурсов.

аа, значит правильно понял.. А зачем мне расширять ресурсы??? Я смотрел много движков где это закладывается, но реально это вообще или очень и очень редко используется... Вот для фреймворков может быть это актуально. А вот для движка для моего сайта вообще не нужно... Я написал класс для управления базой что он и делает... А масштабирование это не только для меня увеличение человека/часов, но и выброшенные деньги  smile Так что мера должна быть в желаниях

Цитата (Fortop @  20.3.2013,  00:13 findReferencedText)
что класс работы с БД не обязан быть синглтоном 
да конечно не обязан(!), но как правило является таковым для простых вопросов (и даже не очень) smile т.к. не нужно ни масштабирование ни множественное подключение
ava
Fortop | 19.03.2013, 23:47 #
Цитата (Gold Dragon @  19.3.2013,  23:36 findReferencedText)
А зачем мне расширять ресурсы???

Конкретно тебе? Без понятия.

А у нас на 300к уников в сутки виртуалка впала в ступор, пришлось поднимать еще две.
ava
baldina | 20.03.2013, 10:25 #
Цитата (Fortop @  19.3.2013,  23:13 findReferencedText)
Масштабирование это увеличение используемых для решения задачи ресурсов.

почти))) увеличение ресурсов - средство, а не цель. цель - увеличение производительности/числа решаемых задач.
еще можно масштабировать функционал. в последнем случае в применении к пхп уместен пример перерастания микрофреймворка в монстрофреймворк, который будет успешен при удачной архитектуре исходника.
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit