文章目录
前言
以下是 Sequelize 中常见的表格操作总结,涵盖字段操作、关联关系、索引和约束等。
所有的操作一般应用在迁移文件所以如果没有迁移文件,需要先创建
sequelize官网文档
- 创建模型
name: 模型的名称
attributes: 模型的属性列表
执行完下面命令,会在目录下创建一个迁移文件,里面就包含了创建表格的执行语句
npx sequelize-cli model:generate --name Article --attributes title:string,content:string
- 运行迁移(所有未执行) 在数据库中实际创建该表
npx sequelize-cli db:migrate
- 创建迁移文件(用于 表格字段增、删、改、查)
如果创建模型之后,想要修改模型,可以再创建一个对应表格的迁移文件,再里面执行文章中的常用指令
npx sequelize-cli migration:generate --name migration-skeleton
- 运行特定迁移
运行刚刚创建的迁移文件,就会同步更新到数据库了。
npx sequelize-cli db:migrate --to xxxx.js
- 查看迁移状态
迁移状态会显示up和down
up为成功,down为失败
npx sequelize-cli db:migrate:status
- 回滚迁移
如果迁移状态显示执行失败,可以手动撤销迁移状态,修改文件之后,重新执行
# 手动标记为未执行
npx sequelize-cli db:migrate:undo --name 20250522084148-article-update-migration.js
一、表格基础操作
1. 创建新表
await queryInterface.createTable('table_name', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
allowNull: false
},
// 其他字段...
});
2. 删除表
await queryInterface.dropTable('table_name');
3. 重命名表
await queryInterface.renameTable('old_table_name', 'new_table_name');
二、字段操作
1. 添加字段
await queryInterface.addColumn('table_name', 'column_name', {
type: Sequelize.DataTypes.INTEGER,
allowNull: true,
defaultValue: null
// 其他选项...
});
2. 删除字段
await queryInterface.removeColumn('table_name', 'column_name');
3. 修改字段
await queryInterface.changeColumn('table_name', 'column_name', {
type: Sequelize.DataTypes.STRING(100), // 修改类型
allowNull: false, // 修改允许null
defaultValue: 'default_value' // 修改默认值
});
4. 重命名字段
await queryInterface.renameColumn('table_name', 'old_column_name', 'new_column_name');
5.查询字段是否存在
防御式编程
在对表格字段操作之前,最好先检测一下是否存在,减少不必要报错。
const tabeCol = await queryInterface.describeTable('tablenames');
if(!tableCol.column){
//如果表格字段 column 不存在执行操作
}
三、索引操作
1. 添加索引
// 普通索引
await queryInterface.addIndex('table_name', ['column1', 'column2'], {
name: 'index_name',
unique: false // 是否唯一
});
// 唯一索引
await queryInterface.addIndex('table_name', ['email'], {
name: 'unique_email',
unique: true
});
2. 删除索引
await queryInterface.removeIndex('table_name', 'index_name');
3.查询索引是否存在
在对索引操作之前,最好也用防御性编程思想
const index = await queryInterface.showIndex('tablenames');
const indexExists = index.find(index => index.name === 'indexname');
if(!indexExists){
//索引不存在,再进行添加索引操作
}
四、约束操作
1. 添加主键约束
await queryInterface.addConstraint('table_name', {
fields: ['id'],
type: 'primary key',
name: 'pk_table_name_id'
});
2. 添加外键约束
await queryInterface.addConstraint('table_name', {
fields: ['foreign_key_column'],
type: 'foreign key',
name: 'fk_constraint_name',
references: {
table: 'referenced_table',
field: 'id'
},
onDelete: 'CASCADE', // 或 'SET NULL', 'RESTRICT'
onUpdate: 'CASCADE'
});
3. 删除约束
await queryInterface.removeConstraint('table_name', 'constraint_name');
五、关联关系操作
1. 一对一关系
// 迁移文件
await queryInterface.addColumn('table1', 'table2_id', {
type: Sequelize.INTEGER,
references: {
model: 'table2',
key: 'id'
},
unique: true // 一对一需要唯一约束
});
// 模型定义
Table1.hasOne(Table2);
Table2.belongsTo(Table1);
2. 一对多关系
// 迁移文件
await queryInterface.addColumn('child_table', 'parent_id', {
type: Sequelize.INTEGER,
references: {
model: 'parent_table',
key: 'id'
}
});
// 模型定义
Parent.hasMany(Child);
Child.belongsTo(Parent);
3. 多对多关系
// 创建联结表
await queryInterface.createTable('table1_table2', {
table1_id: {
type: Sequelize.INTEGER,
references: {
model: 'table1',
key: 'id'
}
},
table2_id: {
type: Sequelize.INTEGER,
references: {
model: 'table2',
key: 'id'
}
},
// 其他字段...
});
// 模型定义
Table1.belongsToMany(Table2, { through: 'table1_table2' });
Table2.belongsToMany(Table1, { through: 'table1_table2' });
六、事务处理最佳实践
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
// 所有操作放在这里
await queryInterface.addColumn(..., { transaction });
await queryInterface.addIndex(..., { transaction });
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
async down(queryInterface) {
const transaction = await queryInterface.sequelize.transaction();
try {
// 逆向操作
await queryInterface.removeIndex(..., { transaction });
await queryInterface.removeColumn(..., { transaction });
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
};
注意:
在操作表格的时候,表名要小写复数
。
比如:
自动生成的迁移文件user,文件名称默认小写,但是模型名称是首字母大写 User
。
在进行操作的时候要写的对应表名是小写复数users
七、实用技巧
- 批量操作:
await Promise.all([
queryInterface.addColumn(...),
queryInterface.addIndex(...)
]);
- 条件操作:
const description = await queryInterface.describeTable('table_name');
if (!description.column_name) {
await queryInterface.addColumn(...);
}
- 数据迁移:
await queryInterface.sequelize.query(`
UPDATE table_name
SET new_column = old_column
WHERE condition
`);
- 使用原始SQL:
await queryInterface.sequelize.query(
'ALTER TABLE table_name ADD COLUMN column_name INT'
);
八、注意事项
-
生产环境警告:
- 大表操作可能锁表,考虑低峰期执行
- 重要操作前备份数据
- 先在测试环境验证迁移脚本
-
命名规范:
- 表名:复数形式,小写,下划线分隔(如
user_profiles
) - 索引名:
idx_table_column
(如idx_users_email
) - 约束名:
fk_table_column
(如fk_posts_author_id
)
- 表名:复数形式,小写,下划线分隔(如
-
性能考虑:
- 添加索引会提高查询速度但降低写入速度
- 外键约束确保数据完整性但增加开销
- 大表修改考虑分批处理
这些操作涵盖了 Sequelize 迁移中最常见的表格操作需求,根据您的具体场景选择适合的操作方式。