Чтобы ответить на ваши вопросы:
MySQL> = 5.1.17 (или> = 5.1.21 для PREPARE
и EXECUTE
заявления) могут использовать подготовленные заявления в кэше запросов . Таким образом, ваша версия MySQL + PHP может использовать подготовленные операторы с кешем запросов. Однако обратите внимание на предостережения относительно кеширования результатов запросов в документации MySQL. Есть много видов запросов, которые нельзя кэшировать или которые бесполезны, даже если они кэшированы. По моему опыту, кеш запросов в любом случае не очень важен. Запросы и схемы требуют специальной конструкции, чтобы максимально использовать кеш. Часто кеширование на уровне приложения в конечном итоге все равно необходимо.
Собственная подготовка не имеет никакого значения для безопасности. Псевдо-подготовленные операторы по-прежнему будут экранировать значения параметров запроса, это будет просто выполняться в библиотеке PDO со строками, а не на сервере MySQL с использованием двоичного протокола. Другими словами, один и тот же код PDO будет одинаково уязвим (или не уязвим) для атак путем внедрения, независимо от ваших EMULATE_PREPARES
настроек. Единственная разница в том, где происходит замена параметра - с EMULATE_PREPARES
, это происходит в библиотеке PDO; без EMULATE_PREPARES
, это происходит на сервере MySQL.
Без этого EMULATE_PREPARES
вы можете получить синтаксические ошибки во время подготовки, а не во время выполнения; with EMULATE_PREPARES
вы получите синтаксические ошибки только во время выполнения, потому что PDO не имеет запроса для передачи MySQL до времени выполнения. Обратите внимание, что это влияет на код, который вы напишете ! Особенно если пользуетесь PDO::ERRMODE_EXCEPTION
!
Дополнительное соображение:
- Существует фиксированная стоимость для
prepare()
(с использованием собственных подготовленных операторов), поэтому prepare();execute()
запрос с собственными подготовленными операторами может быть немного медленнее, чем выдача простого текстового запроса с использованием эмулированных подготовленных операторов. Во многих системах баз данных план запроса для a также prepare()
кэшируется и может использоваться несколькими соединениями, но я не думаю, что MySQL делает это. Поэтому, если вы не используете повторно подготовленный объект оператора для нескольких запросов, ваше общее выполнение может быть медленнее.
В качестве последней рекомендации я думаю, что для более старых версий MySQL + PHP вы должны эмулировать подготовленные операторы, но в ваших самых последних версиях вы должны отключить эмуляцию.
После написания нескольких приложений, использующих PDO, я создал функцию подключения PDO, которая, по моему мнению, имеет лучшие настройки. Вероятно, вам следует использовать что-то подобное или настроить свои предпочтительные настройки:
/**
* Return PDO handle for a MySQL connection using supplied settings
*
* Tries to do the right thing with different php and mysql versions.
*
* @param array $settings with keys: host, port, unix_socket, dbname, charset, user, pass. Some may be omitted or NULL.
* @return PDO
* @author Francis Avila
*/
function connect_PDO($settings)
{
$emulate_prepares_below_version = '5.1.17';
$dsndefaults = array_fill_keys(array('host', 'port', 'unix_socket', 'dbname', 'charset'), null);
$dsnarr = array_intersect_key($settings, $dsndefaults);
$dsnarr += $dsndefaults;
// connection options I like
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
// connection charset handling for old php versions
if ($dsnarr['charset'] and version_compare(PHP_VERSION, '5.3.6', '<')) {
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$dsnarr['charset'];
}
$dsnpairs = array();
foreach ($dsnarr as $k => $v) {
if ($v===null) continue;
$dsnpairs[] = "{$k}={$v}";
}
$dsn = 'mysql:'.implode(';', $dsnpairs);
$dbh = new PDO($dsn, $settings['user'], $settings['pass'], $options);
// Set prepared statement emulation depending on server version
$serverversion = $dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
$emulate_prepares = (version_compare($serverversion, $emulate_prepares_below_version, '<'));
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate_prepares);
return $dbh;
}