PDOstatement (MySQL):将值 0 插入到 bit(1) 字段中会导致 1 写入表中

2022-08-30 16:36:00

我使用 bit(1) 字段来存储布尔值,并使用 PDO 预准备语句写入表中。

这是测试表:

CREATE TABLE IF NOT EXISTS `test` (
  `SomeText` varchar(255) NOT NULL,
  `TestBool` bit(1) NOT NULL DEFAULT b'0'
) ENGINE=MEMORY DEFAULT CHARSET=latin1;

这是测试代码:

$pdo = new PDO("connection string etc") ;
$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES (?,?)') ;
$statement->execute(array("TEST",0)) ;

运行该代码会在 TestBool 下为我提供一行,其值为 1。使用 bindValue() 和 bindParm() 也是同样的事情。我还尝试了命名占位符(而不是?),结果相同。

然后我尝试了:

$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES ("TEST",0)') ;
$statement->execute() ;

它工作正常(TestBool的值为0)。将SQL直接打入MySQL也可以。

请注意,插入 1 始终有效。

那么,为什么占位符无法插入值 0 呢?(我该如何实际做到这一点?


答案 1

BIT列是mysql中的二进制类型(尽管它被记录为数字类型 - 这并不完全正确),我建议由于客户端库的问题(PDO问题证明了这一点)而避免使用它。如果您将列类型修改为TINYINT(1),您将省去很多麻烦

TINYINT(1) 当然会为每行消耗完整的存储字节, 但根据 mysql 文档 BIT(1) 也会这样做。

从: http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html

位存储要求为:大约(M + 7)/ 8字节,这表明BIT(M)列也是字节对齐的。

我也发现了这个:https://bugs.php.net/bug.php?id=50757

因此,您可以检查以下代码是否按预期工作:

$pdo = new PDO("connection string etc") ;
$statement = $pdo->prepare('INSERT INTO `test` (SomeText,TestBool) VALUES (:someText,:testBool)') ;
$statement->bindValue(':someText', "TEST");
$statement->bindValue(':testBool', 0, PDO::PARAM_INT);
$statement->execute();

您也可以尝试使用与PARAM_INT不同的类型提示,即使您成功,我建议更改为TINYINT。


答案 2

默认情况下,pdo 不会对 mysql 驱动程序使用预准备语句,它会通过在后台为你创建动态 sql 来模拟它们。发送到mysql的sql最终是一个单引号0,如“0”,mysql将其解释为字符串,而不是数字。

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

它现在应该可以工作,并且您还将实际使用真正的预准备语句。


推荐