Laravel+MySQL严格模式下未传必填列插入无异常问题排查
问题分析
你遇到的情况是:插入操作未传入NOT NULL且无默认值的列(如start_date、display_period、repetition、display_place、on_click_action等),但MySQL未抛出NOT NULL约束异常,反而将这些列自动填充为0。结合你提供的信息(全局sql_mode包含STRICT_TRANS_TABLES、新库测试正常),问题大概率出在会话级sql_mode、Laravel数据库配置或表级sql_mode的差异上。
排查步骤
1. 检查当前会话的sql_mode
执行以下SQL语句,确认当前数据库连接的会话sql_mode是否包含严格模式规则:
SELECT @@SESSION.sql_mode;
如果结果中没有STRICT_TRANS_TABLES或STRICT_ALL_TABLES,说明当前会话未启用严格模式,MySQL会自动将NULL值转换为对应类型的默认值(数值型为0),而非抛出约束异常。
2. 检查Laravel数据库配置
打开项目根目录下的config/database.php,找到MySQL配置段:
'mysql' => [ // ...其他配置项 'strict' => false, // 重点检查该选项 // ... ],
如果strict被设置为false,Laravel会自动移除MySQL严格模式相关的sql_mode参数,导致数据库进入宽松模式,触发自动填充行为。
3. 检查表级别的sql_mode
部分场景下,表可能被单独设置了sql_mode,覆盖全局配置:
SELECT table_name, table_schema, sql_mode FROM information_schema.tables WHERE table_name = 'ads_sliders';
如果结果中的sql_mode不包含STRICT_TRANS_TABLES,说明表级配置覆盖了全局严格模式规则。
解决方法
1. 启用Laravel严格模式配置
将config/database.php中的strict参数设置为true:
'mysql' => [ // ...其他配置项 'strict' => true, // ... ],
设置为true后,Laravel会自动启用包含STRICT_TRANS_TABLES的严格sql_mode,同时Eloquent ORM会在数据不满足约束时抛出异常,避免自动填充不符合预期的值。
2. 手动修正会话/全局sql_mode
若需临时修复,可在数据库连接后执行:
SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
若要永久生效,修改MySQL配置文件(如my.cnf或my.ini)中的sql_mode参数,重启MySQL服务即可。
3. 修复表级sql_mode
如果表被单独设置了宽松模式,执行以下SQL语句修正:
ALTER TABLE ads_sliders sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
额外说明
- 新库测试正常,说明新库的sql_mode和Laravel配置符合严格模式要求,可对比新旧库的配置差异快速定位问题。
- 对于
start_date这类日期类型列,宽松模式下MySQL会将NULL转换为0000-00-00(若NO_ZERO_DATE规则未生效),你这里出现填充0的情况,是因为涉及的列属于数值型,触发了MySQL的自动类型转换逻辑。
内容的提问来源于stack exchange,提问作者abdul rahman souda

