mysqli_stmt::bind_param()-为每个参数指定除“s”以外的其他数据类型

vhipe2zx  于 2021-06-20  发布在  Mysql
关注(0)|答案(2)|浏览(296)

mysqli_stmt 没有一个 query_params() 函数,我必须自己写。参数arry绑定到语句 bind_param() . 我需要动态地指定变量类型。我可以这样做:

$sType = '';
foreach ($aParameters as $iIndex => $mParameter) {
  if     (is_string($mParameter)) {$sType .= 's';}
  elseif (   is_int($mParameter)) {$sType .= 'i';}
  elseif ( is_float($mParameter)) {$sType .= 'd';}
  elseif (  is_null($mParameter)) {$sType .= 's';}
  elseif (  is_bool($mParameter)) {
    $sType .= 'i';
    $aParameters[$iIndex] = boolval($mParameter);}
  else {
    // trow new Exception(...);
  }
}

但事实证明,mysql/mariadb将布尔、整数和浮点作为字符串发送,数据库服务器将很高兴地将它们转换为列的相应数据类型。似乎我可以跳过这一步,在默认情况下将每个参数作为字符串发送。
是否有任何理由指定其他数据类型而不是 "s" 对于每个参数?
编辑:我刚刚发现了这个主题,它展示了如何使用“b”类型和 mysqli_stmt::send_long_data 当二进制数据包超过 max_allowed_packet 设置。我还了解到,它将比采用 bin2hex() 以文本形式发送字节字符串。

eni9jsuy

eni9jsuy1#

我唯一一次发现使用整数参数很重要是在 LIMIT 条款。

SELECT
...
LIMIT ?, ?

mysql在此上下文中不接受带引号的字符串文本,也不接受字符串类型的参数。必须使用整数。
请参阅参数化pdo查询和'limit'子句-不适用于我的测试。这是一个关于pdo的问题,我没有测试mysqli,但我相信在这种情况下使用整数参数是服务器端mysql的要求。所以它也应该适用于mysqli。
在所有其他情况下(afaik),mysql能够通过读取字符串中的前导数字并忽略后面的任何字符将字符串转换为整数。
@dharman在下面的评论中提到了mysql对 ORDER BY :

SELECT
...
ORDER BY ?

中的整数 ORDER BY 表示按该位置的列排序,而不是按数字的常量值排序:

SELECT
...
ORDER BY 1 -- sorts by the 1st column

但包含该数字的等效字符串值的作用不同。它按字符串的常量值排序,这意味着每一行都是绑定的,排序顺序是任意的。

SELECT
...
ORDER BY '1' -- sorts by a constant value, so all rows are tied

因此,这是查询参数的数据类型很重要的另一种情况。
另一方面,使用序数按中该位置的列进行排序 ORDER BY 或者 GROUP BY 是不赞成的,我们不应该依赖sql的这种用法。

8tntrjer

8tntrjer2#

似乎我可以跳过这一步,在默认情况下将每个参数作为字符串发送。
是的,没错。
是否有任何理由为每个参数指定除“s”以外的其他数据类型?
极其罕见和模糊。到目前为止我能找到
bigint值最好绑定为整数而不是字符串
有报道说施法可能导致错误的执行计划,但我在野外找不到证据
您已经找到的二进制类型,尽管我会质疑在数据库中存储blob的想法本身
达曼提到的那个奇数排序的案子。
不管这种情况有多奇怪,我建议保留类型绑定,但要避免类型嗅探,这样做没有好处,但会破坏数据库。
相反,只需使类型显式但可选,就像我在mysqli helper函数中所做的那样:

function prepared_query($mysqli, $sql, $params, $types = "")
{
    $types = $types ?: str_repeat("s", count($params));
    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    return $stmt;
}

当你不需要它们的时候(大多数时候),只需将类型排除在外:

$sql = "SELECT * FROM tmp_mysqli_helper_test WHERE id > ?";
$res = prepared_query($conn, $sql, [1])->get_result();

但是每次您需要它时,它都已经在这里并且是显式的,您可以设置您想要的确切类型:

$sql = "SELECT * FROM tmp_mysqli_helper_test WHERE id > ?";
$res = prepared_query($conn, $sql, [1], "i")->get_result();

简单,干净,优雅!

相关问题