简体   繁体   English

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

[英]Use same mysqli prepared statement for different queries?

Throughout some testings;在一些测试中; a little question popped up.一个小问题突然出现。 When I usually code database updates;当我通常编码数据库更新时; I usually do this via callbacks which I code in PHP;我通常通过我在 PHP 中编码的回调来做到这一点; to which I simply pass a given mysqli connection object as function argument.我只是将给定的mysqli 连接 object作为 function 参数传递给它。 Executing all queries of for example three queries across the same single connection proved to be much faster than if closing and reopening a DB connection for each query of a given query sequence.在同一个连接上执行例如三个查询的所有查询被证明比为给定查询序列的每个查询关闭和重新打开数据库连接要快得多。 This also works easily with SQL transactions, the connection can be passed along to callbacks without any issues.这也很容易与 SQL 事务一起使用,连接可以毫无问题地传递给回调。

My question is;我的问题是; can you also do this with prepared statement objects ?你也可以用准备好的语句对象来做到这一点吗? What I mean is, considering we successfully established a $conn object, representing the mysqli connection, is stuff like this legit?我的意思是,考虑到我们成功建立了一个$conn object,代表 mysqli 连接,这样的东西合法吗? :

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 );

or is it bad practice;或者这是不好的做法; and you should rather use:你应该使用:

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

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

During the testing;测试期间; I noticed that the method by using a single statement object passed along callbacks works for server calls where I call like 4 not too complicated DB queries via the 4 according callbacks in a row.我注意到通过使用单个语句 object 传递回调的方法适用于服务器调用,我通过连续 4 个相应的回调调用 4 个不太复杂的数据库查询。

When I however do a server call with like 10 different queries, sometimes (yes, only sometimes; for pretty much the same data used across the different executions; so this seems to be weird behavior to me) I get the error "Commands out of sync; you can't run this command now" and some other weird errors I've never experienced, like the amount of variables not matching the amount of parameters;然而,当我使用类似 10 个不同的查询进行服务器调用时,有时(是的,只是有时;对于在不同执行中使用的几乎相同的数据;所以这对我来说似乎是奇怪的行为)我收到错误"Commands out of sync; you can't run this command now"以及我从未遇到过的其他一些奇怪的错误,例如变量数量与参数数量不匹配; although they prefectly do after checking them all.尽管他们在检查完所有内容后都做得很好。 The only way to fix this I found after some research was indeed by using different statement objects for each callback.经过一番研究,我发现解决这个问题的唯一方法确实是为每个回调使用不同的语句对象。 So, I just wondered;所以,我只是想知道; should you actually ALWAYS use ONE prepared statement object for ONE query, which you then may execute N times in a row?您实际上是否应该始终使用一个准备好的语句 object 进行一个查询,然后您可以连续执行 N 次?

Yes.是的。

The "commands out of sync" error is because MySQL protocol is not like http. “命令不同步”错误是因为 MySQL 协议不像 http。 You can't send requests any time you want.您无法随时发送请求。 There is state on the server-side (ie mysqld) that is expecting a certain sequence of requests.在服务器端(即 mysqld)有 state ,它期待一定的请求序列。 This is what's known as a stateful protocol.这就是所谓的有状态协议。

Compare with a protocol like ftp.与 ftp 之类的协议进行比较。 You can do an ls in an ftp client, but the list of files you get back depends on the current working directory.您可以在 ftp 客户端中执行ls ,但您返回的文件列表取决于当前工作目录。 If you were sharing that ftp client connection among multiple functions in your app, you don't know that another function hasn't changed the working directory.如果您在应用程序中的多个功能之间共享 ftp 客户端连接,您不知道另一个 function 没有更改工作目录。 So you can't be sure the file list you get from ls represents the directory you thought you were in.所以你不能确定你从ls得到的文件列表代表你认为你所在的目录。

In MySQL too, there's state on the server-side.在 MySQL 中,服务器端也有 state。 You can only have one transaction open at a time.您一次只能打开一项交易。 You can only have one query executing at a time.您一次只能执行一个查询。 The MySQL client does not allow you to execute a new query where there are still rows to be fetched from an in-progress query. MySQL 客户端不允许您执行新查询,其中仍有要从正在进行的查询中获取的行。 See Commands out of sync in the MySQL doc on common errors.请参阅 MySQL 文档中有关常见错误的命令不同步

So if you pass your statement handle around to some callback functions, how can that function know it's safe to execute the statement?因此,如果您将语句句柄传递给某些回调函数,那么 function 怎么知道执行该语句是安全的?

IMO, the only safe way to use a statement is to use it immediately. IMO,使用语句的唯一安全方法是立即使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM