sql >> Database >  >> RDS >> Mysql

PDO MySQL:PDO::ATTR_EMULATE_PREPARES gebruiken of niet?

Om uw zorgen te beantwoorden:

  1. MySQL>=5.1.17 (of>=5.1.21 voor de PREPARE en EXECUTE statements) kan voorbereide instructies gebruiken in de querycache . Uw versie van MySQL+PHP kan dus voorbereide instructies gebruiken met de querycache. Let echter goed op de kanttekeningen bij het cachen van queryresultaten in de MySQL-documentatie. Er zijn veel soorten zoekopdrachten die niet in de cache kunnen worden opgeslagen of die nutteloos zijn, ook al worden ze in de cache opgeslagen. In mijn ervaring is de querycache sowieso niet vaak een erg grote overwinning. Query's en schema's hebben een speciale constructie nodig om maximaal gebruik te maken van de cache. Vaak is caching op applicatieniveau op de lange termijn toch nodig.

  2. Native voorbereidingen maken geen verschil voor de beveiliging. De pseudo-voorbereide instructies zullen nog steeds ontsnappen aan queryparameterwaarden, het zal alleen worden gedaan in de PDO-bibliotheek met strings in plaats van op de MySQL-server met behulp van het binaire protocol. Met andere woorden, dezelfde PDO-code is even kwetsbaar (of niet-kwetsbaar) voor injectieaanvallen, ongeacht uw EMULATE_PREPARES instelling. Het enige verschil is waar de parametervervanging plaatsvindt - met EMULATE_PREPARES , het komt voor in de PDO-bibliotheek; zonder EMULATE_PREPARES , het komt voor op de MySQL-server.

  3. Zonder EMULATE_PREPARES u kunt tijdens de voorbereidingstijd syntaxisfouten krijgen in plaats van tijdens de uitvoering; met EMULATE_PREPARES u krijgt alleen syntaxisfouten tijdens de uitvoering, omdat PDO tot de uitvoeringstijd geen query heeft om aan MySQL te geven. Merk op dat dit van invloed is op de code die u gaat schrijven ! Vooral als u PDO::ERRMODE_EXCEPTION . gebruikt !

Een extra overweging:

  • Er zijn vaste kosten voor een prepare() (met behulp van native voorbereide instructies), dus een prepare();execute() met native voorbereide instructies kan iets langzamer zijn dan het uitgeven van een platte tekstquery met geëmuleerde voorbereide instructies. Op veel databasesystemen is het queryplan voor een prepare() wordt ook in de cache opgeslagen en kan worden gedeeld met meerdere verbindingen, maar ik denk niet dat MySQL dit doet. Dus als u uw voorbereide instructieobject niet opnieuw gebruikt voor meerdere query's, kan uw algehele uitvoering langzamer zijn.

Als laatste aanbeveling , Ik denk dat je met oudere versies van MySQL+PHP voorbereide instructies moet emuleren, maar met je zeer recente versies moet je emulatie uitschakelen.

Na het schrijven van een paar apps die PDO gebruiken, heb ik een PDO-verbindingsfunctie gemaakt die volgens mij de beste instellingen heeft. Je zou waarschijnlijk zoiets als dit moeten gebruiken of aanpassen aan je voorkeursinstellingen:

/**
 * 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. MariaDB JSON_MERGE_PRESERVE() uitgelegd

  2. Hoe kan ik binaire bestandsgegevens invoegen in een binair SQL-veld met behulp van een eenvoudige insert-instructie?

  3. MySQL cast/converteert automatisch een string naar een nummer?

  4. Pas op voor misleidende gegevens van SET STATISTICS IO