预准备语句实际上如何工作?(菲律宾比索)


How do Prepared Statements actually work? (PHP)

我正在考虑使用node.js/socket.io作为实时用户界面。 我习惯于使用PHP,它有一个很棒的,真正万无一失的准备语句系统。 例如:

$dbh->prepare('SELECT * FROM table WHERE val=:val1 OR val=:val2');
$dbh->execute(array('val1'=>'stuff','val2'=>'more stuff'));

现在,node.js没有这种奢侈,所以我正在考虑自己做一些事情来模拟它。 这里到底发生了什么?

谢谢!

使用

预准备语句或参数化语句以高效率重复执行同一语句。

基本工作流程

预准备语句执行包括两个阶段:准备和执行。在准备阶段,将语句模板发送到数据库服务器。服务器执行语法检查并初始化服务器内部资源供以后使用。

MySQL 服务器支持使用带有 ? 的匿名位置占位符。

1 第一阶段:准备

$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
/* Prepared statement, stage 1: prepare */
if (!($stmt = $mysqli->prepare("INSERT INTO test(id) VALUES (?)"))) {
    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}

2 执行

准备后执行。在执行期间,客户端绑定参数值并将其发送到服务器。服务器从语句模板和绑定值创建语句,以使用先前创建的内部资源执行该语句。

$id = 1;
if (!$stmt->bind_param("i", $id)) {
    echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;
}
if (!$stmt->execute()) {
    echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}

3 重复执行

预准备语句可以重复执行。每次执行时,都会计算绑定变量的当前值并将其发送到服务器。不会再次分析该语句。语句模板不会再次传输到服务器。

/* Prepared statement: repeated execution, only data transferred from client to server */
for ($id = 2; $id < 5; $id++) {
    if (!$stmt->execute()) {
        echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
    }
}
/* explicit close recommended */
$stmt->close();

预准备语句从根本上分离数据和命令 当两者之间的界限因错误输入而变得模糊时,就会发生SQL注入。 将它们分开使注射变得不可能。

若要正确执行此操作,需要具有此功能的该数据库的数据库服务器和客户端。 正如您所发现的,许多数据库客户端实际上并不使用预准备语句功能,而只是转义数据以在查询中用于模拟预准备语句。 这仍然可以被认为是安全的...这些客户端通常经过严格测试。

请注意,当客户端只是模拟预准备语句时,您不会获得预准备语句的性能优势。