Odpověď na vaše obavy:
-
MySQL>=5.1.17 (nebo>=5.1.21 pro
PREPARE
aEXECUTE
příkazy) může použít připravené příkazy v mezipaměti dotazů . Takže vaše verze MySQL+PHP může používat připravené příkazy s mezipamětí dotazů. Pozorně si však poznamenejte upozornění týkající se ukládání výsledků dotazů do mezipaměti v dokumentaci MySQL. Existuje mnoho druhů dotazů, které nelze uložit do mezipaměti nebo které jsou zbytečné, i když jsou uloženy v mezipaměti. Podle mých zkušeností není cache dotazů tak jako tak často velkou výhrou. Dotazy a schémata potřebují speciální konstrukci, aby bylo možné maximálně využít mezipaměť. Ukládání do mezipaměti na úrovni aplikace je často z dlouhodobého hlediska nezbytné. -
Nativní příprava nedělá žádný rozdíl pro bezpečnost. Pseudo-připravené příkazy budou stále unikat hodnotám parametrů dotazu, pouze se to provede v knihovně PDO s řetězci namísto na serveru MySQL pomocí binárního protokolu. Jinými slovy, stejný kód PDO bude stejně zranitelný (nebo nezranitelný) vůči injekčním útokům bez ohledu na váš
EMULATE_PREPARES
nastavení. Jediný rozdíl je v tom, kde dojde k nahrazení parametru -- pomocíEMULATE_PREPARES
, vyskytuje se v knihovně PDO; bezEMULATE_PREPARES
, vyskytuje se na serveru MySQL. -
Bez
EMULATE_PREPARES
můžete dostat syntaktické chyby v době přípravy spíše než v době provádění; pomocíEMULATE_PREPARES
Chyby syntaxe se zobrazí pouze v době provádění, protože PDO nemá dotaz, který by mohl zadat MySQL, až do doby provádění. Všimněte si, že toto ovlivňuje kód, který budete psát ! Zejména pokud používátePDO::ERRMODE_EXCEPTION
!
Další úvaha:
- Za
prepare()
je stanovena pevná cena (pomocí nativních připravených příkazů), takžeprepare();execute()
s nativními připravenými příkazy může být o něco pomalejší než vydávání prostého textového dotazu pomocí emulovaných připravených příkazů. Na mnoha databázových systémech plán dotazů proprepare()
je také v mezipaměti a může být sdílen s více připojeními, ale nemyslím si, že to MySQL dělá. Pokud tedy znovu nepoužijete připravený objekt příkazu pro více dotazů, může být celkové provádění pomalejší.
Jako poslední doporučení , Myslím, že se staršími verzemi MySQL+PHP byste měli emulovat připravené příkazy, ale u vašich nejnovějších verzí byste měli emulaci vypnout.
Po napsání několika aplikací, které používají PDO, jsem vytvořil funkci připojení PDO, která má podle mě nejlepší nastavení. Pravděpodobně byste měli použít něco takového nebo upravit svá preferovaná nastavení:
/**
* 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;
}