sql >> Databasteknik >  >> RDS >> Mysql

PDO MySQL:Använd PDO::ATTR_EMULATE_PREPARES eller inte?

För att svara på dina frågor:

  1. MySQL>=5.1.17 (eller>=5.1.21 för PREPARE och EXECUTE satser) kan använda förberedda satser i frågecachen . Så din version av MySQL+PHP kan använda förberedda satser med frågecachen. Notera dock försiktigt förbehållen för cachning av frågeresultat i MySQL-dokumentationen. Det finns många typer av frågor som inte kan cachelagras eller som är värdelösa trots att de är cachade. Enligt min erfarenhet är frågecachen inte ofta en stor vinst ändå. Frågor och scheman behöver speciell konstruktion för att maximalt utnyttja cachen. Ofta blir cachning på applikationsnivå ändå nödvändigt i det långa loppet.

  2. Native förbereder gör ingen skillnad för säkerheten. De pseudoförberedda satserna kommer fortfarande att undkomma frågeparametervärden, det kommer bara att göras i PDO-biblioteket med strängar istället för på MySQL-servern med det binära protokollet. Med andra ord kommer samma PDO-kod att vara lika sårbar (eller inte sårbar) för injektionsattacker oavsett din EMULATE_PREPARES miljö. Den enda skillnaden är var parameterbytet sker - med EMULATE_PREPARES , det förekommer i PDO-biblioteket; utan EMULATE_PREPARES , det inträffar på MySQL-servern.

  3. Utan EMULATE_PREPARES du kan få syntaxfel vid förberedelsetid snarare än vid körning; med EMULATE_PREPARES du kommer bara att få syntaxfel vid körningstid eftersom PDO inte har en fråga att ge till MySQL förrän vid körningstid. Observera att detta påverkar koden du kommer att skriva ! Speciellt om du använder PDO::ERRMODE_EXCEPTION !

En ytterligare övervägande:

  • Det finns en fast kostnad för en prepare() (med inbyggda förberedda satser), så en prepare();execute() med inbyggda förberedda uttalanden kan det vara lite långsammare än att utfärda en vanlig textfråga med emulerade förberedda uttalanden. På många databassystem planerar frågan för en prepare() är också cachad och kan delas med flera anslutningar, men jag tror inte att MySQL gör detta. Så om du inte återanvänder ditt förberedda satsobjekt för flera frågor kan din totala exekvering bli långsammare.

Som en sista rekommendation , Jag tycker att med äldre versioner av MySQL+PHP bör du emulera förberedda uttalanden, men med dina allra senaste versioner bör du stänga av emulering.

Efter att ha skrivit några appar som använder PDO så har jag gjort en PDO-anslutningsfunktion som har vad jag tycker är de bästa inställningarna. Du bör förmodligen använda något liknande detta eller justera till dina föredragna inställningar:

/**
 * 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. Får datumlista inom ett intervall i PostgreSQL

  2. Hur ansluter jag till en MySQL-databas i Python?

  3. När behöver jag använda start-/slutblock och nyckelordet Go i SQL Server?

  4. Hur man väljer ett kolumnnamn med ett mellanslag i MySQL