Drizzle ORM中timestamp.defaultNow()在PlanetScale报错但生效问题
问题分析
你在使用Drizzle ORM创建包含created_at列的users表时,推送schema到PlanetScale出现ER_INVALID_DEFAULT错误,提示created_at默认值无效,但最终表结构(包括索引)却成功同步到了数据库。
错误原因
- Vitess校验时机问题:PlanetScale基于Vitess,在执行
ALTER TABLE添加索引的操作时,会额外校验表中已有列的默认值合法性。虽然表创建时已经成功生成了created_at列,但后续添加索引的操作触发了Vitess的二次校验,导致抛出错误。 - 语法兼容性差异:
defaultNow()生成的默认值语法,在Vitess环境下不符合严格校验规则。Vitess对MySQL timestamp类型的默认值处理有细微差异,更倾向于显式的CURRENT_TIMESTAMP写法。 - 错误信息误导:错误栈显示的SQL是创建索引的操作,但提示指向
created_at,这是因为Vitess执行ALTER操作时会检查表的整体结构,而非仅当前操作的对象。
解决方法
以下是几种可行的修复方案:
1. 显式指定CURRENT_TIMESTAMP表达式
将defaultNow()替换为显式SQL表达式,确保Vitess能正确识别默认值:
createdAt: timestamp('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
2. 改用datetime类型
如果timestamp的默认值校验问题难以解决,可将created_at改为datetime类型,功能上和timestamp在多数场景下一致,且Vitess对其默认值处理更宽松:
createdAt: datetime('created_at').notNull().defaultNow(),
3. 升级Drizzle Kit版本
检查当前使用的Drizzle Kit版本,升级到最新稳定版,新版本可能已修复和PlanetScale/Vitess的兼容性问题:
npm install drizzle-kit@latest --save-dev
验证结果
修改后重新执行drizzle-kit push:mysql命令,应该不会再出现created_at默认值的错误提示,同时表结构和索引能正常同步。
内容的提问来源于stack exchange,提问作者Parzival
相关产品推荐
相关产品推荐

