strict_mode=true暴露sql不规范:not null字段未赋值、非法类型插入、group by不合规、时间字段无默认值、零日期被拒,需修正sql和表结构而非关闭严格模式。

TP5.1 数据库配置中 strict_mode => true 会强制 MySQL 以严格模式运行,这本身是推荐的安全实践,但若项目长期在非严格模式下开发,开启后极易触发各类“突然报错”,并非框架缺陷,而是暴露了原有 SQL 的不规范写法。
字段缺失或默认值不合法导致 INSERT 失败
MySQL 严格模式下,以下情况会直接抛出异常而非静默修正:
- 插入数据时未给
NOT NULL字段赋值(哪怕该字段有默认值,但代码里没显式传) - 向
INT字段插入空字符串''或字符串'abc'(非数字) - 向
DATETIME字段插入'0000-00-00'或非法日期格式 - 使用
Db::insert()传入的数组缺某个必填字段,且数据库未设默认值
TP5.1 不会自动补全字段或转换类型——它原样把数据交给 PDO,错误由 MySQL 层返回。常见报错如:Field 'xxx' doesn't have a default value 或 Data truncated for column 'xxx'。
GROUP BY 查询报错:only_full_group_by 生效
开启 strict_mode 后,MySQL 默认启用 ONLY_FULL_GROUP_BY。TP5.1 的 group() 方法若只写 group('status'),但 select() 中又取了 id、name 等非分组字段,就会报错:
Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'xxx' which is not functionally dependent on columns in GROUP BY clause
这不是 TP5.1 的 bug,而是你写的 SQL 本身不符合 SQL92 标准。修复方式不是关 strict_mode,而是明确写出所有非聚合字段到 group() 中,或改用聚合函数包裹,例如:field('status, COUNT(*) as total, MAX(create_time) as last_time')。
时间字段自动填充失效或报错
TP5.1 模型中常设 protected $createTime = 'create_time';,依赖 MySQL 的 DEFAULT CURRENT_TIMESTAMP。但在 strict_mode 下:
- 若表结构中
create_time是DATETIME类型但未设DEFAULT CURRENT_TIMESTAMP,插入时会因字段为NOT NULL且无默认值而失败 - 若手动传
null或空字符串给时间字段,MySQL 直接拒绝,不会自动转成当前时间 - TP5.1 的自动时间戳逻辑(如
autoWriteTimestamp)只负责拼 SQL,不干预数据库校验逻辑
建议:建表时明确定义 create_time DATETIME DEFAULT CURRENT_TIMESTAMP,并在模型中统一用 datetime 类型校验输入,避免传空。
零日期/零值被拦截,影响老业务逻辑
很多老项目习惯用 '0000-00-00' 表示“未知日期”,或用 0 表示“未设置”。strict_mode 下这些值会被 MySQL 拒绝,报错类似:Incorrect date value: '0000-00-00'。
TP5.1 无法绕过这一层限制。应对策略包括:
- 将相关字段改为允许 NULL,并在代码中用
null替代零日期 - 前端/表单层拦截非法日期,不提交
0000-00-00 - 迁移期可临时在 MySQL 配置中加
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE(去掉后两项),但不建议长期使用
不复杂但容易忽略











