如何在knex.js中为tinyint类型主键设置自增属性
问题描述
需要将数据表主键设置为tinyint类型,在knex.js中使用specificType()方法配置时,仅写tinyint(1) PRIMARY KEY可以正常生效,但追加自增属性后执行迁移触发运行报错。
报错信息
migration file "20220609065447_create_roles_table.ts" failed migration failed with error: create table `roles` (`id` tinyint(1) PRIMARY KEY AUTO_INCREMENT, `name` varchar(30) not null, `permission` varchar(50) not null, `created_at` datetime default CURRENT_TIMESTAMP, `updated_at` datetime default CURRENT_TIMESTAMP) - SQLITE_ERROR: near "AUTO_INCREMENT": syntax error create table `roles` (`id` tinyint(1) PRIMARY KEY AUTO_INCREMENT, `name` varchar(30) not null, `permission` varchar(50) not null, `created_at` datetime default CURRENT_TIMESTAMP, `updated_at` datetime default CURRENT_TIMESTAMP) - SQLITE_ERROR: near "AUTO_INCREMENT": syntax error Error: create table `roles` (`id` tinyint(1) PRIMARY KEY AUTO_INCREMENT, `name` varchar(30) not null, `permission` varchar(50) not null, `created_at` datetime default CURRENT_TIMESTAMP, `updated_at` datetime default CURRENT_TIMESTAMP) - SQLITE_ERROR: near "AUTO_INCREMENT": syntax error
原错误代码
import { Knex } from 'knex'; export async function up(knex: Knex): Promise<void> { await knex.schema.createTable('roles', (table) => { table.specificType('id', 'tinyint(1) PRIMARY KEY AUTO_INCREMENT'); table.string('name', 30).notNullable(); table.string('permission', 50).notNullable(); table.timestamp('created_at').defaultTo(knex.fn.now()); table.timestamp('updated_at').defaultTo(knex.fn.now()); }); } export async function down(knex: Knex): Promise<void> { await knex.schema.dropTable('roles'); }
报错原因
- 报错明确返回
SQLITE_ERROR,说明当前执行迁移的数据库是SQLite,而代码里写的AUTO_INCREMENT是MySQL专属的自增关键字,SQLite不识别该语法,因此抛出语法错误。 - SQLite的自增主键语法为
INTEGER PRIMARY KEY AUTOINCREMENT,和MySQL语法不通用,直接硬编码单数据库方言的SQL片段无法跨库执行。 - 额外注意:
tinyint(1)有符号取值范围为-128127,无符号取值范围为0255,作为主键如果后续数据量超过255条会出现溢出问题,仅适合数据量固定且极小的场景(比如角色表这类枚举值少的表)。
解决方案
如果需要同时兼容MySQL(生产环境)和SQLite(本地/测试环境),在迁移代码中判断当前数据库客户端类型,分别配置对应语法即可:
import { Knex } from 'knex'; export async function up(knex: Knex): Promise<void> { await knex.schema.createTable('roles', (table) => { const dbClient = knex.client.config.client; // MySQL 环境使用 tinyint 自增主键 if (dbClient === 'mysql' || dbClient === 'mysql2') { table.specificType('id', 'tinyint UNSIGNED PRIMARY KEY AUTO_INCREMENT'); } else { // SQLite 等其他环境使用knex内置的自增主键方法,自动适配对应语法 table.increments('id').primary(); } table.string('name', 30).notNullable(); table.string('permission', 50).notNullable(); table.timestamp('created_at').defaultTo(knex.fn.now()); table.timestamp('updated_at').defaultTo(knex.fn.now()); }); } export async function down(knex: Knex): Promise<void> { await knex.schema.dropTable('roles'); }
如果确定服务只使用MySQL数据库,直接检查knex配置文件里的client参数是否填对为mysql/mysql2,不要错误配置为sqlite3即可正常执行。
内容的提问来源于stack exchange,提问作者simon Shim
相关产品推荐
相关产品推荐

