You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何PHP PDO会忽略MariaDB的NOT NULL约束?

解决PDO插入MariaDB违反NOT NULL约束不抛异常的问题

你的场景中,person表的alias1字段定义为NOT NULL且无默认值,但通过PDO执行省略该字段的INSERT语句时,数据库自动插入了空字符串而非抛出错误,导致PDO未触发异常。直接用SQL脚本执行相同操作却能正常报错,核心原因是PDO连接会话的sql_mode未启用严格模式。

原因分析

MariaDB/MySQL在非严格模式下,遇到NOT NULL字段未赋值的情况,会对字符串类型字段自动填充空字符串、数值类型填充0,而不会抛出约束违反错误。此时数据库返回的是成功状态,PDO即便设置了ERRMODE_EXCEPTION也不会触发异常。而你直接用SQL脚本执行时,当前会话的sql_mode可能已经启用了严格模式,所以会报错。

解决方案

在PDO连接时,强制设置会话的sql_mode为严格模式(至少包含STRICT_TRANS_TABLES,这是InnoDB表的严格模式核心参数),让数据库在违反约束时返回错误,从而触发PDO的异常机制。

实现方式

有两种常用方法:

  • 在PDO初始化命令中添加sql_mode设置
  • 连接成功后单独执行SET sql_mode语句

方法1:修改PDO连接的初始化命令

修改PDO构造函数的MYSQL_ATTR_INIT_COMMAND参数,合并编码设置与严格模式设置:

$conn = new PDO(
    'mysql:host=localhost;dbname=tibsi-data', 'root', '',
    array(
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4; SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'"
    )
);

注:把SET NAMES utf8改成utf8mb4,与你的表编码保持一致,避免编码不一致问题。

方法2:连接后执行设置语句

如果初始化命令存在长度限制(部分环境下会有),可以在连接成功后单独执行设置:

$conn = new PDO(
    'mysql:host=localhost;dbname=tibsi-data', 'root', '',
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4")
);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 设置严格模式
$conn->exec("SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'");

修改后的完整测试脚本

<?php

$conn = new PDO(
    'mysql:host=localhost;dbname=tibsi-data', 'root', '',
    array(
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4; SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'"
    )
);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

try {
    $stm = $conn->prepare("INSERT INTO person (firstname) VALUES (:firstname)");
    $stm->bindValue(':firstname', 'Mike');

    // 无需判断execute返回值,ERRMODE_EXCEPTION会自动抛出异常
    $stm->execute();
    $stm->closeCursor();

    $insertId = $conn->lastInsertId();

    header('HTTP/1.1 200 OK');
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode(array('id' => $insertId));
    exit;
} catch (Exception $e) {
    header('HTTP/1.1 500 Internal Server Error');
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode(array('error' => $e->getMessage()));
    exit;
} catch (Error $e) {
    header('HTTP/1.1 500 Internal Server Error');
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode(array('error' => $e->getMessage()));
    exit;
}

验证效果

修改后执行脚本,数据库会因alias1未赋值违反NOT NULL约束返回错误,PDO会捕获该错误并抛出异常,最终返回500响应和错误信息,符合预期。

内容的提问来源于stack exchange,提问作者Lycodo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:34:56