告别数据库迁移噩梦:Fastify+Sequelize/TypeORM实战指南
你是否还在为Node.js项目的数据库迁移头疼?手动执行SQL脚本导致环境不一致?版本回滚时数据丢失?本文将带你用Fastify结合Sequelize与TypeORM两大ORM框架,构建安全、可追溯的数据库迁移流程,从此告别"在我电脑上能运行"的尴尬。
为什么需要数据库迁移?
数据库迁移(Database Migration)是管理数据库 schema 变更的自动化方式,就像代码的版本控制一样。在Fastify项目中,它能帮你:
- 避免手动执行SQL导致的团队协作混乱
- 实现开发/测试/生产环境的 schema 一致性
- 安全地进行版本回滚,防止数据丢失
- 保留完整的变更历史,便于审计和问题排查
官方文档推荐使用迁移工具管理 schema 变更,具体可参考docs/Guides/Database.md中"Migrations"章节的最佳实践。
Fastify+Sequelize:企业级迁移方案
Sequelize是Node.js生态中最成熟的ORM之一,提供完整的迁移系统和事务支持,适合中大型项目使用。
1. 环境搭建
首先安装必要依赖:
npm install sequelize @types/sequelize pg # 以PostgreSQL为例
npm install --save-dev sequelize-cli
2. 初始化迁移配置
创建Sequelize配置文件sequelize.config.js:
module.exports = {
development: {
dialect: 'postgres',
url: 'postgres://postgres@localhost/fastify_db'
},
production: {
dialect: 'postgres',
url: process.env.DATABASE_URL,
dialectOptions: {
ssl: { rejectUnauthorized: false }
}
}
};
3. 创建迁移脚本
使用Sequelize CLI生成用户表迁移:
npx sequelize-cli migration:generate --name create-users
编辑生成的迁移文件(位于migrations/目录):
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
username: {
type: Sequelize.STRING,
unique: true,
allowNull: false
},
email: {
type: Sequelize.STRING,
unique: true,
allowNull: false,
validate: {
isEmail: true
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW')
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.fn('NOW')
}
});
},
down: async (queryInterface) => {
await queryInterface.dropTable('users');
}
};
4. 在Fastify中集成
创建Fastify插件plugins/sequelize.js:
const fp = require('fastify-plugin');
const { Sequelize } = require('sequelize');
module.exports = fp(async (fastify, options) => {
const sequelize = new Sequelize(options.url, {
dialect: options.dialect,
logging: fastify.log.info
});
try {
await sequelize.authenticate();
fastify.log.info('Sequelize connection has been established successfully');
} catch (error) {
fastify.log.error('Unable to connect to the database:', error);
throw error;
}
fastify.decorate('sequelize', sequelize);
fastify.addHook('onClose', async (fastify) => {
await fastify.sequelize.close();
fastify.log.info('Sequelize connection closed');
});
}, { name: 'fastify-sequelize' });
在应用入口注册插件:
// src/app.js
const fastify = require('fastify')();
const sequelizeConfig = require('../sequelize.config');
fastify.register(require('./plugins/sequelize'), {
...sequelizeConfig[process.env.NODE_ENV || 'development']
});
// 运行迁移命令
fastify.after(async () => {
await fastify.sequelize.getQueryInterface().showAllTables();
});
fastify.listen({ port: 3000 }, (err) => {
if (err) throw err;
});
Fastify+TypeORM:现代化TypeScript方案
TypeORM是TypeScript优先的ORM框架,支持Active Record和Data Mapper模式,适合需要强类型保障的项目。
1. 基础配置
安装依赖:
npm install typeorm reflect-metadata pg # PostgreSQL适配器
npm install --save-dev @types/node
创建TypeORM配置文件ormconfig.ts:
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
url: process.env.DATABASE_URL || 'postgres://postgres@localhost/fastify_db',
entities: ['src/entities/**/*.ts'],
migrations: ['src/migrations/**/*.ts'],
synchronize: false, // 生产环境必须关闭
logging: true
});
2. 定义实体与迁移
创建用户实体src/entities/User.ts:
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
username: string;
@Column({ unique: true })
email: string;
@CreateDateColumn()
createdAt: Date;
}
生成迁移文件:
npx typeorm-ts-node-commonjs migration:generate src/migrations/CreateUser -d src/ormconfig.ts
3. Fastify集成插件
创建TypeORM插件src/plugins/typeorm.ts:
import { FastifyInstance, FastifyPluginOptions } from 'fastify';
import fp from 'fastify-plugin';
import { AppDataSource } from '../ormconfig';
export default fp(async (fastify: FastifyInstance, options: FastifyPluginOptions) => {
if (!AppDataSource.isInitialized) {
await AppDataSource.initialize();
fastify.log.info('TypeORM initialized');
}
fastify.decorate('db', AppDataSource);
fastify.addHook('onClose', async (fastify) => {
if (AppDataSource.isInitialized) {
await AppDataSource.destroy();
fastify.log.info('TypeORM connection closed');
}
});
}, { name: 'fastify-typeorm' });
在应用中使用:
// src/server.ts
import fastify from 'fastify';
import typeormPlugin from './plugins/typeorm';
import { User } from './entities/User';
const server = fastify();
server.register(typeormPlugin);
server.get('/users', async (request, reply) => {
const userRepository = server.db.getRepository(User);
return await userRepository.find();
});
server.listen({ port: 3000 }, (err) => {
if (err) throw err;
});
两种方案对比与选型建议
| 特性 | Sequelize | TypeORM |
|---|---|---|
| 类型支持 | 部分支持 | 原生TypeScript |
| 学习曲线 | 平缓 | 较陡 |
| 生态成熟度 | ★★★★★ | ★★★★☆ |
| 迁移功能 | 命令式API | 自动生成+命令式 |
| 性能 | 优秀 | 优秀 |
| 社区规模 | 大 | 中 |
选型建议:
- 传统JavaScript项目或需要快速上手:选Sequelize
- TypeScript项目或需要强类型保障:选TypeORM
- 企业级应用:优先考虑Sequelize的稳定性
- 新基建项目:推荐TypeORM的现代化特性
最佳实践与避坑指南
1. 迁移文件版本控制
始终将迁移文件纳入Git版本控制,参考Fastify官方文档的版本管理建议。
2. 生产环境安全措施
- 禁用
synchronize: true(TypeORM)或alter: true(Sequelize) - 迁移前自动备份数据
- 使用事务包装迁移操作:
// Sequelize事务示例
module.exports = {
up: async (queryInterface) => {
await queryInterface.sequelize.transaction(async (t) => {
await queryInterface.createTable('users', { /* ... */ }, { transaction: t });
await queryInterface.addIndex('users', ['email'], { transaction: t });
});
}
};
3. 与Fastify生命周期集成
利用Fastify的生命周期钩子管理迁移执行时机:
// 在应用启动时运行迁移
fastify.addHook('onReady', async () => {
if (process.env.NODE_ENV === 'production') {
const { execSync } = require('child_process');
execSync('npx typeorm-ts-node-commonjs migration:run -d src/ormconfig.ts', {
stdio: 'inherit'
});
}
});
总结
数据库迁移是企业级应用不可或缺的基础设施。通过本文介绍的Fastify+Sequelize/TypeORM方案,你可以:
- 实现数据库schema的版本化管理
- 确保多环境一致性部署
- 安全地进行版本升级与回滚
- 获得清晰的变更历史审计 trail
选择适合项目需求的ORM框架,遵循最佳实践,就能彻底告别数据库迁移的混乱时代。完整示例代码可参考Fastify官方数据库指南和本文配套的迁移脚本模板。
提示:生产环境建议使用专门的迁移服务(如GitHub Actions)自动执行迁移,避免手动操作风险。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



