Ответ 1
Лучший способ действий для вас будет зависеть от того, как вы приближаетесь к вашему доступу к данным. Существует три подхода:
- Использование хранимых процедур
- Сохраняйте запросы в коде (но включите все ваши запросы в функции и исправьте все, чтобы использовать PDO для параметров, как упоминалось ранее)
- Используйте инструмент ORM
Если вы хотите передать свой собственный исходный SQL-код в механизм базы данных, тогда хранимые процедуры будут способом идти, если все, что вы хотите сделать, это получить исходный SQL из вашего PHP-кода, но сохраните его относительно без изменений. Хранимые процедуры против сырых SQL-дискуссий - это битва святой войны, но К. Скотт Аллен делает превосходный момент - хотя и одноразовый - в статье о базы данных версий:
Во-вторых, хранимые процедуры в моих глазах не понравились. Я пришел из школы индоктринации WinDNA, в которой говорилось, что хранимые процедуры должны использоваться все время. Сегодня я вижу хранимые процедуры как уровень API для базы данных. Это хорошо, если вам нужен уровень API на уровне базы данных, но я вижу, что множество приложений несут накладные расходы на создание и поддержку дополнительного уровня API, который им не нужен. В этих приложениях хранимые процедуры являются скорее бременем, чем преимуществом.
Я склоняюсь к тому, чтобы не использовать хранимые процедуры. Я работал над проектами, в которых БД имеет API, открытый через хранимые процедуры, но хранимые процедуры могут налагать некоторые свои ограничения, и эти проекты в той или иной степени используют динамически генерируемый необработанный SQL-код для доступа к БД.
Наличие уровня API в БД дает лучшее разграничение ответственности между командой БД и командой разработчиков за счет некоторой гибкости, которую вы имели бы, если бы запрос содержался в коде, однако проекты PHP менее вероятны чтобы иметь достаточное количество команд, чтобы извлечь выгоду из этого разграничения.
Концептуально, вероятно, вы должны иметь версию своей базы данных. Практически, однако, у вас гораздо больше шансов иметь только ваш код, чем вы, чтобы иметь версию вашей базы данных. Вероятно, вы измените свои запросы при внесении изменений в свой код, но если вы меняете запросы в хранимых процедурах, хранящихся в базе данных, то вы, вероятно, не будете проверять их при проверке кода и теряете многие из преимуществ управления версиями для значительной области вашего приложения.
Независимо от того, выбираете ли вы не использовать хранимые процедуры, вы должны, по крайней мере, обеспечить, чтобы каждая операция базы данных хранилась в независимой функции, а не была встроена в каждый из ваших скриптов страниц - по существу, уровень API для ваша БД, которая поддерживается и версируется с вашим кодом. Если вы используете хранимые процедуры, это будет эффективно означать, что у вас есть два уровня API для вашей БД: один с кодом и один с БД, что может казаться излишне усложняющим, если ваш проект не имеет отдельных команд. Я конечно делаю.
Если проблема является одной из аккуратности кода, есть способы сделать код с SQL застрявшим в нем более презентабельным, и класс UserManager, показанный ниже, является хорошим способом запуска - класс содержит только запросы, которые относятся к пользователю ', каждый запрос имеет свой собственный метод в классе, и запросы отступываются в операторы подготовки и отформатированы так же, как вы отформатируете их в хранимой процедуре.
// UserManager.php:
class UserManager
{
function getUsers()
{
$pdo = new PDO(...);
$stmt = $pdo->prepare('
SELECT u.userId as id,
u.userName,
g.groupId,
g.groupName
FROM user u
INNER JOIN group g
ON u.groupId = g.groupId
ORDER BY u.userName, g.groupName
');
// iterate over result and prepare return value
}
function getUser($id) {
// db code here
}
}
// index.php:
require_once("UserManager.php");
$um = new UserManager;
$users = $um->getUsers();
foreach ($users as $user) echo $user['name'];
Однако, если ваши запросы очень похожи, но у вас есть огромное количество перестановок в ваших условиях запроса, таких как сложный пейджинг, сортировка, фильтрация и т.д., возможно, инструмент для преобразования объектов/реляций, хотя процесс капитального ремонта ваш существующий код для использования инструмента может быть довольно сложным.
Если вы решили исследовать инструменты ORM, вы должны посмотреть Propel, компонент ActiveRecord Yii или PHP ORM с королем-папой, Doctrine. Каждый из них дает вам возможность программно создавать запросы к вашей базе данных со всей сложной логикой. Doctrine является наиболее полнофункциональной версией, позволяющей вам создавать шаблоны своей базы данных с помощью вложенного шаблона дерева из коробки.
С точки зрения производительности, хранимые процедуры являются самыми быстрыми, но обычно не намного выше raw sql. Инструменты ORM могут оказывать значительное влияние на производительность несколькими способами - неэффективное или избыточное выполнение запросов, огромный файл ввода-вывода при загрузке библиотек ORM для каждого запроса, динамическое генерирование SQL для каждого запроса... все эти вещи могут иметь влияние, но использование инструмента ORM может значительно увеличить доступную вам мощность с гораздо меньшим количеством кода, чем создание собственного уровня БД с помощью ручных запросов.
Гэри Ричардсон абсолютно прав, хотя, если вы собираетесь продолжать использовать SQL в своем коде, вы всегда должны использовать подготовленные инструкции PDO для обработки параметров независимо о том, используете ли вы запрос или хранимую процедуру. Санитация ввода выполняется для вас PDO.
// optional
$attrs = array(PDO::ATTR_PERSISTENT => true);
// create the PDO object
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass", $attrs);
// also optional, but it makes PDO raise exceptions instead of
// PHP errors which are far more useful for debugging
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('INSERT INTO venue(venueName, regionId) VALUES(:venueName, :regionId)');
$stmt->bindValue(":venueName", "test");
$stmt->bindValue(":regionId", 1);
$stmt->execute();
$lastInsertId = $pdo->lastInsertId();
var_dump($lastInsertId);
Предостережение: при условии, что идентификатор равен 1, выведенный выше script будет выводить string(1) "1"
. PDO->lastInsertId()
возвращает идентификатор в виде строки независимо от того, является ли фактический столбец целым числом или нет. Это, вероятно, никогда не будет проблемой для вас, поскольку PHP выполняет автоматическое литье строк в целые числа.
Далее выведет bool(true)
:
// regular equality test
var_dump($lastInsertId == 1);
но если у вас есть код, ожидающий, что значение будет целочисленным, например is_int или PHP "действительно, действительно, на 100% равно" оператору:
var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);
вы можете столкнуться с некоторыми проблемами.
Изменить: Хорошее обсуждение хранимых процедур здесь