เพื่อตอบข้อกังวลของคุณ:
MySQL> = 5.1.17 (หรือ> = 5.1.21 สำหรับPREPARE
และEXECUTE
งบ) สามารถใช้งบเตรียมในแคชแบบสอบถาม ดังนั้น MySQL + PHP เวอร์ชันของคุณจึงสามารถใช้คำสั่งที่เตรียมไว้กับแคชแบบสอบถาม อย่างไรก็ตามโปรดสังเกตข้อควรระวังสำหรับการแคชผลการค้นหาในเอกสาร MySQL มีแบบสอบถามหลายประเภทที่ไม่สามารถแคชได้หรือไม่มีประโยชน์แม้ว่าจะถูกแคชไว้ก็ตาม จากประสบการณ์ของฉันแคชการสืบค้นมักไม่ใช่ชัยชนะที่ยิ่งใหญ่มากนัก คิวรีและสคีมาจำเป็นต้องมีโครงสร้างพิเศษเพื่อใช้ประโยชน์สูงสุดจากแคช บ่อยครั้งที่การแคชระดับแอปพลิเคชันกลายเป็นสิ่งที่จำเป็นในระยะยาว
การเตรียมแบบดั้งเดิมไม่ได้สร้างความแตกต่างใด ๆ สำหรับความปลอดภัย คำสั่งที่เตรียมหลอกจะยังคงหลบหนีค่าพารามิเตอร์การสืบค้นซึ่งจะทำในไลบรารี PDO ด้วยสตริงแทนบนเซิร์ฟเวอร์ MySQL โดยใช้โปรโตคอลไบนารี กล่าวอีกนัยหนึ่งรหัส PDO เดียวกันจะเสี่ยงต่อการโจมตีแบบแทรกซึม (หรือไม่เสี่ยง) เท่า ๆ กันโดยไม่คำนึงถึงEMULATE_PREPARES
การตั้งค่าของคุณ ข้อแตกต่างเพียงอย่างเดียวคือการแทนที่พารามิเตอร์เกิดขึ้น - โดยEMULATE_PREPARES
เกิดขึ้นในไลบรารี PDO โดยไม่EMULATE_PREPARES
เกิดขึ้นบนเซิร์ฟเวอร์ MySQL
โดยที่EMULATE_PREPARES
คุณอาจไม่ได้รับข้อผิดพลาดทางไวยากรณ์ในเวลาเตรียมการแทนที่จะเป็นเวลาดำเนินการ กับEMULATE_PREPARES
คุณจะได้รับข้อผิดพลาดทางไวยากรณ์ในเวลาการดำเนินการเพราะ PDO ไม่ได้มีแบบสอบถามให้กับ MySQL จนกว่าจะถึงเวลาการปฏิบัติ โปรดทราบว่าสิ่งนี้มีผลกับโค้ดที่คุณจะเขียน ! โดยเฉพาะอย่างยิ่งถ้าคุณใช้PDO::ERRMODE_EXCEPTION
!
ข้อพิจารณาเพิ่มเติม:
- มีค่าใช้จ่ายคงที่สำหรับ a
prepare()
(โดยใช้คำสั่งที่จัดเตรียมแบบเนทีฟ) ดังนั้นprepare();execute()
คำสั่งที่มีการเตรียมแบบเนทีฟอาจช้ากว่าการออกแบบสอบถามข้อความธรรมดาโดยใช้คำสั่งจำลองที่เตรียมไว้เล็กน้อย ในระบบฐานข้อมูลจำนวนมากแผนการสืบค้นสำหรับ a prepare()
จะถูกแคชไว้เช่นกันและอาจแชร์กับการเชื่อมต่อที่หลากหลาย แต่ฉันไม่คิดว่า MySQL จะทำเช่นนี้ ดังนั้นหากคุณไม่นำออบเจ็กต์คำสั่งที่เตรียมไว้มาใช้ซ้ำสำหรับการสืบค้นหลายครั้งการดำเนินการโดยรวมอาจช้า
ตามคำแนะนำสุดท้ายฉันคิดว่าด้วย MySQL + PHP เวอร์ชันเก่าคุณควรเลียนแบบข้อความที่เตรียมไว้ แต่ด้วยเวอร์ชันล่าสุดของคุณคุณควรปิดการจำลอง
หลังจากเขียนแอพสองสามตัวที่ใช้ PDO ฉันได้สร้างฟังก์ชันการเชื่อมต่อ PDO ซึ่งมีสิ่งที่ฉันคิดว่าเป็นการตั้งค่าที่ดีที่สุด คุณควรใช้สิ่งนี้หรือปรับแต่งการตั้งค่าที่คุณต้องการ:
/**
* 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;
}