sql >> Database teknologi >  >> RDS >> Mysql

PDO MySQL:Brug PDO::ATTR_EMULATE_PREPARES eller ej?

Sådan besvarer du dine bekymringer:

  1. MySQL>=5.1.17 (eller>=5.1.21 for PREPARE og EXECUTE udsagn) kan bruge forberedte udsagn i forespørgselscachen . Så din version af MySQL+PHP kan bruge forberedte sætninger med forespørgselscachen. Vær dog opmærksom på forbeholdene for cache-forespørgselsresultater i MySQL-dokumentationen. Der er mange slags forespørgsler, som ikke kan cachelagres, eller som er ubrugelige, selvom de er cachelagret. Efter min erfaring er forespørgselscachen alligevel ikke ofte en særlig stor gevinst. Forespørgsler og skemaer kræver en speciel konstruktion for at udnytte cachen maksimalt. Ofte ender caching på applikationsniveau alligevel med at være nødvendig i det lange løb.

  2. Native forbereder gør ikke nogen forskel for sikkerheden. De pseudo-forberedte sætninger vil stadig undslippe forespørgselsparameterværdier, det vil bare blive gjort i PDO-biblioteket med strenge i stedet for på MySQL-serveren ved hjælp af den binære protokol. Med andre ord vil den samme PDO-kode være lige så sårbar (eller ikke-sårbar) over for injektionsangreb uanset din EMULATE_PREPARES indstilling. Den eneste forskel er, hvor parameterudskiftningen finder sted - med EMULATE_PREPARES , det forekommer i PDO-biblioteket; uden EMULATE_PREPARES , forekommer det på MySQL-serveren.

  3. Uden EMULATE_PREPARES du kan få syntaksfejl ved forberedelsestidspunktet i stedet for ved udførelsestidspunkt; med EMULATE_PREPARES du vil kun få syntaksfejl ved udførelsestidspunktet, fordi PDO ikke har en forespørgsel at give til MySQL før udførelsestidspunktet. Bemærk, at dette påvirker den kode, du vil skrive ! Især hvis du bruger PDO::ERRMODE_EXCEPTION !

En yderligere overvejelse:

  • Der er en fast pris for en prepare() (ved at bruge native forberedte sætninger), så en prepare();execute() med native forberedte sætninger kan være lidt langsommere end at udstede en almindelig tekstforespørgsel ved hjælp af emulerede forberedte sætninger. På mange databasesystemer planlægger forespørgslen for en prepare() er også cachelagret og kan deles med flere forbindelser, men jeg tror ikke, MySQL gør dette. Så hvis du ikke genbruger dit forberedte sætningsobjekt til flere forespørgsler, kan din samlede udførelse være langsommere.

Som en endelig anbefaling , Jeg tror, ​​at du med ældre versioner af MySQL+PHP bør efterligne forberedte udsagn, men med dine helt nyere versioner bør du slå emulering fra.

Efter at have skrevet et par apps, der bruger PDO, har jeg lavet en PDO forbindelsesfunktion, som har, hvad jeg synes er de bedste indstillinger. Du bør sandsynligvis bruge noget som dette eller justere til dine foretrukne indstillinger:

/**
 * 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;
}


  1. SQL:IF-sætning i WHERE-sætning

  2. Hvordan henter jeg alle rækkerne i min DB?

  3. Skift adgangskoden til et SQL Server-login

  4. Sådan gør du RAND() deterministisk i SQL Server