Để trả lời mối quan tâm của bạn:
MySQL> = 5.1.17 (hoặc> = 5.1.21 cho các câu lệnh PREPARE
và EXECUTE
) có thể sử dụng các câu lệnh được chuẩn bị trong bộ đệm 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 được chuẩn bị với bộ đệm truy vấn. Tuy nhiên, hãy lưu ý cẩn thận các cảnh báo cho 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 trong bộ nhớ cache hoặc vô dụng mặc dù chúng được lưu trữ. Theo kinh nghiệm của tôi, bộ đệm truy vấn thường không phải là một chiến thắng rất lớn. Các truy vấn và lược đồ cần xây dựng đặc biệt để sử dụng tối đa bộ đệm. Thường thì bộ nhớ đệm cấp ứng dụng cuối cùng vẫn cần thiết trong thời gian dài.
Chuẩn bị bản địa không làm cho bất kỳ sự khác biệt cho an ninh. Các câu lệnh được chuẩn bị giả sẽ vẫn thoát các giá trị tham số truy vấn, nó sẽ chỉ được thực hiện trong thư viện PDO bằng các chuỗi thay vì trên máy chủ MySQL sử dụ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 thương) đối với các cuộc tấn công tiêm chích bất kể EMULATE_PREPARES
cài đặt của bạn . Sự khác biệt duy nhất là nơi xảy ra sự thay thế tham số - 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.
Không có EMULATE_PREPARES
bạn có thể nhận được lỗi cú pháp tại thời gian chuẩn bị thay vì tại thời gian thực hiện; với EMULATE_PREPARES
bạn sẽ chỉ nhận được lỗi cú pháp tại thời điểm thực hiện vì PDO không có truy vấn để cung cấp cho MySQL cho đến khi thời gian thực hiện. 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 sự xem xét bổ sung:
- Có một chi phí cố định cho một
prepare()
(sử dụng các câu lệnh được chuẩn bị riêng), do đó, một prepare();execute()
câu lệnh được chuẩn bị riêng 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 đơn giản bằng cách sử dụng các câu lệnh được chuẩn bị mô phỏng. Trên nhiều hệ thống cơ sở dữ liệu, kế hoạch truy vấn cho a prepare()
cũng được lưu trong bộ nhớ cache và có thể được chia sẻ với nhiều kết nối, nhưng tôi không nghĩ MySQL làm đ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ị cho nhiều truy vấn thì việc 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ĩ với các phiên bản cũ hơn của MySQL + PHP, bạn nên mô phỏng các câu lệnh đã chuẩn bị, nhưng với các phiên bản gần đây của bạn, bạn nên tắt phần 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ó 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;
}