Mysql
 sql >> Baza danych >  >> RDS >> Mysql

PDO MySQL:użyć PDO::ATTR_EMULATE_PREPARES czy nie?

Aby odpowiedzieć na Twoje wątpliwości:

  1. MySQL>=5.1.17 (lub>=5.1.21 dla PREPARE i EXECUTE 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ę.

  2. 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; bez EMULATE_PREPARES , występuje na serwerze MySQL.

  3. Bez EMULATE_PREPARES możesz otrzymać błędy składni w czasie przygotowania, a nie w czasie wykonywania; z EMULATE_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żywasz PDO::ERRMODE_EXCEPTION !

Dodatkowa uwaga:

  • Istnieje stały koszt prepare() (przy użyciu natywnych przygotowanych instrukcji), więc prepare();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ń dla prepare() 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;
}


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wstaw MySQL do z jednej bazy danych w innej

  2. Czy używać SET NAMES

  3. Jak zmienić nazwę przesłanego pliku przed zapisaniem go w katalogu?

  4. SQLSTATE[HY093]:Nieprawidłowy numer parametru:parametr nie został zdefiniowany

  5. Jak sprawić, by MySQL poprawnie obsługiwał kodowanie UTF-8?