对不同的查询使用相同的 mysqli 准备语句?

Use same mysqli prepared statement for different queries?

通过一些测试;弹出一个小问题。当我通常编写数据库更新代码时;我通常通过在 PHP 中编码的回调来执行此操作;我只是将给定的 mysqli connection object 作为函数参数传递给它。事实证明,通过同一个连接执行所有查询(例如三个查询)比为给定查询序列的每个查询关闭和重新打开数据库连接要快得多。这也很容易与 SQL 交易一起工作,连接可以毫无问题地传递给回调。

我的问题是;你也可以用 prepared statement objects 做这个吗?我的意思是,考虑到我们成功建立了一个代表 mysqli 连接的 $conn 对象,这样的东西是合法的吗? :

function select_users( $users_id, $stmt ) {

  $sql = "SELECT username FROM users where ID = ?";

  mysqli_stmt_prepare( $stmt, $sql );
  mysqli_stmt_bind_param( $stmt, "i", $users_id );
  mysqli_stmt_execute( $stmt );

  return mysqli_stmt_get_result( $stmt );

}

function select_labels( $artist, $stmt ) {

  $sql = "SELECT label FROM labels where artist = ?";

  mysqli_stmt_prepare( $stmt, $sql );
  mysqli_stmt_bind_param( $stmt, "s", $artist );
  mysqli_stmt_execute( $stmt );

  return mysqli_stmt_get_result( $stmt );

}

$stmt = mysqli_stmt_init( $conn );

$users = select_users( 1, $stmt );
$rappers = select_labels( "rapperxyz", $stmt );

或者这是不好的做法;你应该使用:

$stmt_users = mysqli_stmt_init( $conn );
$stmt_rappers = mysqli_stmt_init( $conn );

$users = select_users( 1, $stmt_users );
$rappers = select_labels( "rapperxyz", $stmt_rappers );

测试期间;我注意到通过使用沿回调传递的单个语句对象的方法适用于服务器调用,我通过连续 4 个相应的回调调用 4 个不太复杂的数据库查询。

然而,当我用大约 10 个不同的查询进行服务器调用时,有时(是的,只是有时;对于在不同执行中使用的几乎相同的数据;所以这对我来说似乎是奇怪的行为)我得到了错误 "Commands out of sync; you can't run this command now" 和其他一些我从未遇到过的奇怪错误,比如变量的数量与参数的数量不匹配;尽管他们在检查完所有内容后完美地做到了。经过一些研究,我发现解决这个问题的唯一方法确实是为每个回调使用不同的语句对象。所以,我只是想知道;你真的应该总是对一个查询使用一个准备好的语句对象,然后你可以连续执行 N 次吗?

是的。

“命令不同步”错误是因为 MySQL 协议不像 http。您无法随时发送请求。服务器端(即 mysqld)有一个状态,它期待特定的请求序列。这就是所谓的有状态协议。

与 ftp 等协议进行比较。您可以在 ftp 客户端中执行 ls,但返回的文件列表取决于当前工作目录。如果您在应用中的多个函数之间共享 ftp 客户端连接,您不知道另一个函数没有更改工作目录。所以你不能确定你从 ls 得到的文件列表代表你认为你所在的目录。

在 MySQL 中,服务器端也有状态。您一次只能打开一个交易。您一次只能执行一个查询。 MySQL 客户端不允许您在仍有行要从正在进行的查询中提取的情况下执行新查询。请参阅 MySQL 文档中关于常见错误的 Commands out of sync

因此,如果您将语句句柄传递给某些回调函数,该函数如何知道执行该语句是安全的?

IMO,使用语句的唯一安全方法是立即使用它。