Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

PDO MySQL:Sử dụng PDO ::ATTR_EMULATE_PREPARES hay không?

Để giải đáp những băn khoăn của bạn:

  1. MySQL> =5.1.17 (hoặc> =5.1.21 cho PREPAREEXECUTE câu lệnh) có thể sử dụng câu lệnh đã chuẩn bị sẵn trong bộ nhớ cache truy vấn . Vì vậy, phiên bản MySQL + PHP của bạn có thể sử dụng các câu lệnh đã chuẩn bị sẵn với bộ đệm truy vấn. Tuy nhiên, hãy lưu ý cẩn thận những lưu ý đối với kết quả truy vấn bộ đệm trong tài liệu MySQL. Có nhiều loại truy vấn không thể được lưu vào bộ nhớ cache hoặc vô dụng mặc dù chúng đã được lưu vào bộ nhớ cache. Theo kinh nghiệm của tôi, dù sao thì bộ đệm truy vấn thường không phải là một chiến thắng quá lớn. Các truy vấn và lược đồ cần có cấu trúc đặc biệt để sử dụng tối đa bộ đệm. Thường thì bộ nhớ đệm cấp ứng dụng vẫn cần thiết về lâu dài.

  2. Bản gốc chuẩn bị không tạo ra bất kỳ sự khác biệt nào về bảo mật. Các câu lệnh giả được chuẩn bị vẫn sẽ thoát khỏi các giá trị tham số truy vấn, nó sẽ chỉ được thực hiện trong thư viện PDO với các chuỗi thay vì trên máy chủ MySQL bằng giao thức nhị phân. Nói cách khác, cùng một mã PDO sẽ dễ bị tổn thương như nhau (hoặc không dễ bị tấn công) đối với các cuộc tấn công tiêm bất kể EMULATE_PREPARES của bạn là gì thiết lập. Sự khác biệt duy nhất là nơi thay thế tham số xảy ra - với EMULATE_PREPARES , nó xảy ra trong thư viện PDO; không có EMULATE_PREPARES , nó xảy ra trên máy chủ MySQL.

  3. Không có EMULATE_PREPARES bạn có thể gặp lỗi cú pháp tại thời điểm chuẩn bị thay vì thời điểm thực thi; với EMULATE_PREPARES bạn sẽ chỉ gặp lỗi cú pháp tại thời điểm thực thi vì PDO không có truy vấn để cung cấp cho MySQL cho đến thời điểm thực thi. Lưu ý rằng điều này ảnh hưởng đến mã bạn sẽ viết ! Đặc biệt nếu bạn đang sử dụng PDO::ERRMODE_EXCEPTION !

Một cân nhắc bổ sung:

  • Có một chi phí cố định cho một prepare() (sử dụng các câu lệnh chuẩn bị sẵn), do đó, một prepare();execute() với các câu lệnh được chuẩn bị sẵn có thể chậm hơn một chút so với việc đưa ra một truy vấn văn bản thuần túy bằng cách sử dụng các câu lệnh chuẩn bị được mô phỏng. Trên nhiều hệ thống cơ sở dữ liệu, kế hoạch truy vấn cho một prepare() cũng được lưu vào bộ nhớ đệm và có thể được chia sẻ với nhiều kết nối, nhưng tôi không nghĩ MySQL làm được điều này. Vì vậy, nếu bạn không sử dụng lại đối tượng câu lệnh đã chuẩn bị của mình cho nhiều truy vấn, quá trình thực thi tổng thể của bạn có thể chậm hơn.

Như một đề xuất cuối cùng , Tôi nghĩ rằng với các phiên bản MySQL + PHP cũ hơn, bạn nên mô phỏng các câu lệnh đã chuẩn bị sẵn, nhưng với các phiên bản gần đây nhất, bạn nên tắt tính năng mô phỏng.

Sau khi viết một vài ứng dụng sử dụng PDO, tôi đã tạo một chức năng kết nối PDO có chức năng mà tôi nghĩ là cài đặt tốt nhất. Bạn có thể nên sử dụng một cái gì đó như thế này hoặc điều chỉnh các cài đặt ưa thích của bạn:

/**
 * 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. Cách sử dụng JDBC để kết nối cơ sở dữ liệu MySql

  2. Lỗi MySQL # 1071 - Khóa được chỉ định quá dài; độ dài khóa tối đa là 767 byte

  3. Sao lưu tự động hoặc thường xuyên dữ liệu mysql

  4. Làm cách nào để liên kết các tham số với một truy vấn DB thô trong Laravel được sử dụng trên một mô hình?

  5. Di chuyển Cơ sở dữ liệu Oracle sang MySQL trên AWS, Phần 2