Aby odpowiedzieć na Twoje wątpliwości:
-
MySQL>=5.1.17 (lub>=5.1.21 dla
PREPARE
iEXECUTE
oświadczenia) może używać przygotowanych instrukcji w pamięci podręcznej zapytań . Tak więc Twoja wersja MySQL+PHP może używać przygotowanych instrukcji z pamięcią podręczną zapytań. Należy jednak zwrócić uwagę na zastrzeżenia dotyczące buforowania wyników zapytań w dokumentacji MySQL. Istnieje wiele rodzajów zapytań, których nie można buforować lub które są bezużyteczne, mimo że są buforowane. Z mojego doświadczenia wynika, że pamięć podręczna zapytań i tak nie jest często bardzo dużą wygraną. Zapytania i schematy wymagają specjalnej konstrukcji, aby maksymalnie wykorzystać pamięć podręczną. Często buforowanie na poziomie aplikacji i tak jest konieczne na dłuższą metę. -
Preparaty natywne nie mają żadnego znaczenia dla bezpieczeństwa. Pseudopreparowane instrukcje nadal będą pomijać wartości parametrów zapytania, po prostu zostaną zrobione w bibliotece PDO z ciągami znaków zamiast na serwerze MySQL przy użyciu protokołu binarnego. Innymi słowy, ten sam kod PDO będzie równie podatny (lub niepodatny) na ataki wstrzykiwania, niezależnie od Twojego
EMULATE_PREPARES
ustawienie. Jedyna różnica polega na tym, gdzie następuje zamiana parametrów — za pomocąEMULATE_PREPARES
, występuje w bibliotece PDO; bezEMULATE_PREPARES
, występuje na serwerze MySQL. -
Bez
EMULATE_PREPARES
możesz otrzymać błędy składni w czasie przygotowania, a nie w czasie wykonywania; zEMULATE_PREPARES
błędy składniowe pojawią się tylko w czasie wykonania, ponieważ PDO nie ma zapytania do MySQL do czasu wykonania. Pamiętaj, że ma to wpływ na kod, który napiszesz ! Zwłaszcza jeśli używaszPDO::ERRMODE_EXCEPTION
!
Dodatkowa uwaga:
- Istnieje stały koszt
prepare()
(przy użyciu natywnych przygotowanych instrukcji), więcprepare();execute()
z natywnymi przygotowanymi instrukcjami może być nieco wolniejsze niż wydawanie zwykłego tekstu zapytania przy użyciu emulowanych przygotowanych instrukcji. W wielu systemach baz danych plan zapytań dlaprepare()
jest również buforowany i może być udostępniany wielu połączeniom, ale nie sądzę, aby MySQL to robił. Więc jeśli nie użyjesz ponownie przygotowanego obiektu instrukcji dla wielu zapytań, ogólne wykonanie może być wolniejsze.
Jako ostateczna rekomendacja , myślę, że w przypadku starszych wersji MySQL+PHP należy emulować przygotowane instrukcje, ale w najnowszych wersjach należy wyłączyć emulację.
Po napisaniu kilku aplikacji, które używają PDO, stworzyłem funkcję połączenia PDO, która ma, jak sądzę, najlepsze ustawienia. Powinieneś prawdopodobnie użyć czegoś takiego lub dostosować preferowane ustawienia:
/**
* 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;
}