如何在Knex.js中创建引用UUID主键的外键?附报错及代码
问题现象
使用Knex.js编写MySQL数据库迁移脚本时,campaigns表可正常创建,创建关联该表的user表时触发如下语法错误:
Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'unsigned, `name` varchar(255) not null, `role` varchar(255) not null, `instagram' at line 1
原始问题代码如下:
exports.up = function (knex) { knex.schema .createTable("campaigns", (table) => { table.uuid("id").primary(); table.string("name").notNullable(); table.text("description").notNullable(); table.string("location").notNullable(); table.timestamp("created_at").defaultTo(knex.fn.now()).notNullable(); }) .createTable("user", (table) => { table.uuid("id").primary(); table .uuid("campaign_id") .unsigned() .notNullable() .references("id") .inTable("campaigns"); table.string("name").notNullable(); table.string("role").notNullable(); table.string("instagram").notNullable(); table.string("email").notNullable(); table.bigint("number").notNullable(); })
错误原因
unsigned()是Knex针对整数类型字段提供的约束方法,仅适用于TINYINT/INT/BIGINT等数值型字段,作用是设置字段为无符号数值。- Knex的
uuid类型在MySQL中会被映射为CHAR(36)字符串类型,字符串类型不支持unsigned约束,生成SQL时会额外拼接无效的unsigned关键字,直接触发MySQL语法报错,和报错日志中提示的错误位置完全匹配。 - 原始代码没有返回Knex的Promise调用链,Knex无法感知迁移执行的时序状态,即使修复语法问题也可能出现表创建顺序错乱的问题。
- 额外注意:
user是MySQL内置保留关键字,直接作为表名使用容易引发标识符冲突。
正确实现方案
修复点说明:
- 删除UUID类型
campaign_id字段上无效的.unsigned()调用 - 为迁移方法返回Promise链,保证表按定义顺序执行创建
- 建议将表名
user改为更通用的users,规避保留字冲突 - 补充迁移回滚逻辑,保证
down操作可正常执行
exports.up = function (knex) { // 必须return Promise链,否则Knex无法正确感知迁移执行状态 return knex.schema .createTable("campaigns", (table) => { table.uuid("id").primary(); table.string("name").notNullable(); table.text("description").notNullable(); table.string("location").notNullable(); table.timestamp("created_at").defaultTo(knex.fn.now()).notNullable(); }) .createTable("users", (table) => { table.uuid("id").primary(); // UUID是字符串类型,不需要加unsigned约束 table .uuid("campaign_id") .notNullable() .references("id") .inTable("campaigns"); table.string("name").notNullable(); table.string("role").notNullable(); table.string("instagram").notNullable(); table.string("email").notNullable(); table.bigint("number").notNullable(); }); }; // 迁移回滚逻辑,注意外键表要先删除 exports.down = function (knex) { return knex.schema .dropTableIfExists("users") .dropTableIfExists("campaigns"); };
内容的提问来源于stack exchange,提问作者130000c
相关产品推荐
相关产品推荐

