Работа с базами данных DBM

Задача
Необходима более устойчивая и масштабируемая технология хранения простых данных, чем текстовых файлов.

Решение
Для доступа к базе данных типа DBM следует использовать уровень абстракции DBA:

$dbh = dba_open('fish.db','c','gdbm') or die($php_errormsg);
// извлекаем и модифицируем значения
if (dba_exists('flounder',$dbh)) {
$flounder_count = dba_fetch('flounder',$dbh);
$flounder_count++;
dba_replace('flounder',$flounder_count);
print "Updated the flounder count.";
} else {
dba_insert('flounder',1);
print "Started the flounder count.";
}
// больше нет ни одной тилапии
dba_delete('tilapia',$dbh);
// какая у нас рыбка?
for ($key = dba_firstkey($dbh); $key !== false; $key = dba_nextkey($dbh)) {
$value = dba_fetch($key);
print "$key: $value\n";
}
dba_close($dbh);

Обсуждение
PHP способен поддерживать несколько различных типов машин баз данных DBM: GDBM, NDBM, DB2, DB3, DBM и CDB. Уровень абстракции DBA позволяет использовать одни и те же функции на любой машине DBM. Все машины хранят пары ключ/значение.


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

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

$user = $_SERVER['argv'][1];
$password = $_SERVER['argv'][2];
$data_file = '/tmp/users.db';
$dbh = dba_open($data_file,'c','gdbm') or die("Can't open db $data_file");
if (dba_exists($user,$dbh)) {
print "User $user exists. Changing password.";
} else {
print "Adding user $user.";
}
dba_replace($user,$password,$dbh) or die("Can't write
to database $data_file");
dba_close($dbh);

Функция dba_open() возвращает дескриптор файла DBM (или false в случае ошибки). Она принимает три аргумента. Первый аргумент –это имя файла DBM, а второй аргумент – режим открытия файла.


Режим 'r' открывает доступ к существующей базе данных только на чтение, а 'w' открывает существующую базу данных на чтение и запись. Режим 'c' открывает доступ к базе данных на чтение/запись и создает базу данных, если она не существует. Последний режим, 'n', делает то же самое, что и режим 'c', но если база данных уже существует, то очищает ее. Третий аргумент функции dba_open() указывает используемый DBM-обработчик; в данном примере это 'gdbm'. Чтобы определить, какой DBM-обработчик был скомпилирован во время инсталляции PHP, загляните в секцию «DBA» вывода функции phpinfo(). Строка «Supported handlers» показывает то, что было выбрано.
Функция dba_exists() позволяет определить, есть ли такой ключ в базе данных DBM. Она принимает два аргумента: строку-ключ и дескриптор файла DBM. Она ищет ключ в файле DBM и возвращает true, если находит его (или false, если поиск неудачен). Функция dba_replace() принимает три аргумента: ключ-строку, строковое значение и дескриптор файла DBM. Она помещает ключ/значение в файл DBM. Если элемент с данным ключом уже существует, она заменяет этот элемент новым значением.

Для закрытия базы данных вызовите функцию dba_close(). Файл DBM, открытый функцией dba_open(), автоматически закрывается при завершении работы сценария, но необходимо явно вызвать функцию dba_close(), чтобы закрыть постоянные соединения, созданные функцией dba_popen().

С помощью функций dba_firstkey() и dba_nextkey() можно пройти в цикле по всем ключам в файле DBM, а функция dba_fetch() позволяет извлекать значения, связанные с каждым ключом.


Приведенная ниже программа вычисляет общую длину всех паролей в файле DBM:

$data_file = '/tmp/users.db';
$total_length = 0;
if (! ($dbh = dba_open($data_file,'r','gdbm'))) {
die("Can't open database $data_file");
}
$k = dba_firstkey($dbh);
while ($k) {
$total_length += strlen(dba_fetch($k,$dbh));
$k = dba_nextkey($dbh);
}
print "Total length of all passwords is $total_length characters.";
dba_close($dbh);

Функция dba_firstkey() инициализирует переменную $k значением первого ключа в файле DBM. При каждом прохождении цикла while функция dba_fetch() извлекает значение, соответствующее ключу $k, и переменная $total_length увеличивается на длину значения (вычисленногопосредством функции strlen()). С помощью функции dba_nextkey() переменной $k присваивается значение следующего ключа из файла.

Функция serialize() позволяет реализовать хранение сложных данных в файле DBM – точно так же, как это делается в случае текстового файла. Однако данные в файле DBM могут быть индексированы ключом:

$dbh = dba_open('users.db','c','gdbm') or die($php_errormsg);
// читаем данные и выполняем обратное преобразование
// из последовательной формы
if ($exists = dba_exists($_REQUEST['username'])) {
$serialized_data = dba_fetch($_REQUEST['username'])
or die($php_errormsg);
$data = unserialize($serialized_data);
} else {
$data = array();
}
// обновляем значения
if ($_REQUEST['new_password']) {
$data['password'] = $_REQUEST['new_password'];
}
$data['last_access'] = time();
// записываем данные обратно в файл
if ($exists) {
dba_replace($_REQUEST['username'],serialize($data));
} else {
dba_insert($_REQUEST['username'],serialize($data));
}
dba_close($dbh);

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


Структурные данные такого типа относятся к ба-
зам данных SQL.

В некоторых областях каждый DBM-обработчик ведет себя по-разному. Например, GDBM предоставляет внутреннюю блокировку. Если один процесс открыл файл GDBM в режиме чтения/записи, то еще один вызов функции dba_open() для открытия того же самого файла в режиме чтения/записи закончится неудачей. Однако обработчик DB3 не предоставляет внутренней блокировки; для этого необходимо написать дополнительный код, как объясняется в рецепте 18.24 для текстовых файлов. Две DBA-функции также имеют особенности, связанные с типами баз данных: dba_optimize() и dba_sync(). Функция dba_optimize() вызывает специфическую для обработчика функцию оптимизации файла DBM. В настоящее время она реализована только для GDBM, при этом вызывается его функция gdbm_reorganize(). Функцияdba_sync() вызывает специфическую для обработчика функцию синхронизации файла DBM. В случае DB2 и DB3 вызывается их функция sync(). В случае GDBM вызывается его функция gdbm_sync(). Если применяются другие DBM-обработчики, то ничего не выполняется.

Использование базы данных DBM представляет собой шаг вперед по сравнению с текстовыми файлами, но при этом большинство возможностей SQL-баз данных недоступны.


Структура данных ограничена парами ключ/значение, а устойчивость блокировки сильно зависит от DBM-обработчика. Все же выбор DBM-обработчиков может быть вполне оправдан, если требуется в основном только чтение данных при большой нагрузке; например, крупнейшая база данных кинофильмов в Интернете – сайт http://www.imdb.com/ – основана на DBM.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Автоматическое присваивание уникальных значений идентификаторов
Выполнение запросов к базе данных SQL
Извлечение строк без цикла
Кэширование запросов и результатов
Модификация данных в базе данных SQL

Вернуться в раздел: PHP / 10. Доступ к базам данных