PHP mysql PDO在不可为null的列中设置0,而不是在输入为null时引发异常

PHP mysql PDO在不可为null的列中设置0,而不是在输入为null时引发异常,php,mysql,pdo,Php,Mysql,Pdo,使用PHP PDO for mysql更新具有空值的不可空字段时,我无法生成错误或异常。直接执行sql会产生预期的错误 PDO中的所有内容都会导致status_id字段的值设置为0,而不是异常或错误,表明该字段不允许空值 $stmt_handler = $this->db_handler->prepare( "UPDATE faxes SET metadata = :metadata, status_id = :status_id, created = :created,

使用PHP PDO for mysql更新具有空值的不可空字段时,我无法生成错误或异常。直接执行sql会产生预期的错误

PDO中的所有内容都会导致status_id字段的值设置为0,而不是异常或错误,表明该字段不允许空值

$stmt_handler = $this->db_handler->prepare(
  "UPDATE faxes SET metadata = :metadata, status_id = :status_id, 
  created = :created, updated = :updated, content = :content, 
  vendor_fax_id = :vendor_fax_id WHERE id = :id");
$stmt_handler->bindParam(':id', $fax->id);
$stmt_handler->bindParam(':metadata', $fax->metadata);
$stmt_handler->bindParam(':status_id', $fax->status_id); // tried different combinations
$stmt_handler->bindParam(':created', $fax->created);
$stmt_handler->bindParam(':updated', $fax->updated);
$stmt_handler->bindParam(':content', $fax->content);
$stmt_handler->bindParam(':vendor_fax_id', $fax->vendor_fax_id);
$stmt_handler->execute();
我尝试了不同的组合,并将PDO::ATTR_EMULATE_设置为false(如本问题所建议的)

我的原始装订:

bindParam(':status_id', $fax->status_id);
试用

bindValue(':status_id', null, PDO::PARAM_INT);
bindValue(':status_id', null, PDO::PARAM_NULL);
bindValue(':status_id', 'NULL', PDO::PARAM_INT);
bindValue(':status_id', 'NULL', PDO::PARAM_NULL);
bindValue(':status_id', null);
bindValue(':status_id', 'NULL');
PHP版本:PHP 5.3.10-1ubuntu3

MYSQL服务器版本:5.5.28-0ubuntu0.12.10.1

按评论编辑

mysql> show columns from faxes;
+---------------+--------------+------+-----+-------------------+-----------------------------+
| Field         | Type         | Null | Key | Default           | Extra                       |
+---------------+--------------+------+-----+-------------------+-----------------------------+
| id            | char(36)     | NO   | PRI | NULL              |                             |
| vendor_fax_id | char(36)     | YES  | UNI | NULL              |                             |
| metadata      | varchar(255) | NO   |     | NULL              |                             |
| status_id     | int(10)      | NO   | MUL | NULL              |                             |
| created       | datetime     | NO   |     | NULL              |                             |
| updated       | timestamp    | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| content       | mediumblob   | NO   |     | NULL              |                             |
+---------------+--------------+------+-----+-------------------+-----------------------------+
7 rows in set (0.00 sec)

我试过这个小例子

$host = 'localhost';
$database = 'test';
$dbuser = 'USER';
$dbpasswd = '****';
$dsn = "mysql:host=$host;dbname=$database";
$pdo = new PDO($dsn, $dbuser, $dbpasswd);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$sth = $pdo->prepare('insert into test values(?, ?)');
$id = 2;
$name = null;
$sth->bindParam(1, $id);
$sth->bindParam(2, $name);
$sth->execute() or die(implode(';', $sth->errorInfo()));
这个试验台

create table test (
id int not null,
name text not null);
它给了我

PHP Fatal error:  Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null' in /tmp/a.php:15
Stack trace:
#0 /tmp/a.php(15): PDOStatement->execute()
#1 {main}
  thrown in /tmp/a.php on line 15
在命令行上

更新:

将语句更改为

update test set name = ? where id = ?

执行时无错误,并将
name
设置为空字符串

更新2:

我终于明白了。这与PDO无关,而是特定于MySQL的

请参阅,向下搜索“非空”

如果通过设置为NULL来更新已声明为非NULL的列,则如果启用了严格SQL模式,则会发生错误;否则,列将被设置为列数据类型的隐式默认值,并且警告计数将递增。对于数字类型,隐式默认值为0,对于字符串类型,空字符串(“”),对于日期和时间类型,隐式默认值为“0”。见第11.5节“数据类型默认值”


因此,这种行为被记录在案。如果要获得错误,必须启用严格SQL模式。

只有在mysql中启用严格模式时,才会在更新时产生此错误。在.ini文件中,检查:

[mysqld]
..snipped..
sql_mode="some values here"
如果它不存在,请添加它,并确保应用了严格的设置,例如:

[mysqld]
..snipped..
sql_mode="STRICT_TRANS_TABLES"
重新启动服务器,然后查看新的错误:)

我复制了你的问题,但没有,当我添加并重新启动mysql时,错误开始出现


当非空字段中已经有值时,Mysql仍然可以运行,因此不会产生硬错误。只有严格模式才会强制它抛出一个。你是否100%认为该列没有应用默认值
0
?如果它在更新sql中工作,请尝试此操作,看看它是否工作听起来与本周早些时候的问题类似。与往返mySQL相反,为什么不先检查null,然后手动引发异常呢。不会直接回答问题,但效率更高(对于阅读代码的其他用户来说也更清晰)。用我的产品(换句话说,它在工作)。PHP5.4.9/win32、MySQL 5.5.25/win32 i的insert语句也能正常工作。你能试一下你的例子的更新语句吗?谢谢,谢谢你的帮助。正如@Ben Griffith提到的,当我打开严格模式时,我得到了预期的错误。
[mysqld]
..snipped..
sql_mode="STRICT_TRANS_TABLES"