当前位置: 首页 > news >正文

数据库迁移migration

📦 数据库迁移(Database Migration)详解

数据库迁移 就像是数据库的版本控制系统(类似 Git 对代码的管理),用于管理数据库结构(表、字段、索引等)的变更历史!

🎯 核心作用

想象一个场景:

❌ 没有迁移的噩梦

开发者A: "我加了一个 email 字段"
开发者B: "什么?我这边运行报错了!"
开发者C: "生产环境的表结构是什么样的?"
所有人: "😱 不知道啊..."结果:
- 每个人的数据库结构不一样
- 无法追踪谁改了什么
- 部署到生产环境时不知道要改什么
- 回滚困难

✅ 有迁移的优雅

开发者A: 创建迁移文件 "添加email字段"
团队成员: 运行 npm run migrate
生产环境: 运行 npm run migrate结果:
- ✅ 所有环境数据库结构一致
- ✅ 每个变更都有记录
- ✅ 可以回滚
- ✅ 可追溯历史

📋 什么是数据库迁移?

数据库迁移 = 数据库结构变更的脚本文件

它记录了:

  • 📝 要做什么改动(up)
  • 🔙 如何撤销改动(down)
  • ⏰ 改动的时间
  • 📄 改动的描述

🔄 迁移的工作原理

1. 迁移文件结构

// 20240219065551-add-email-field.js
module.exports = {// ⬆️ UP: 执行迁移(前进)up: async (queryInterface, Sequelize) => {await queryInterface.addColumn('users', 'email', {type: Sequelize.STRING,allowNull: false});},// ⬇️ DOWN: 回滚迁移(后退)down: async (queryInterface, Sequelize) => {await queryInterface.removeColumn('users', 'email');}
};

2. 迁移执行过程

1. 数据库中有一个特殊表(SequelizeMeta)记录已执行的迁移
2. 运行 migrate 命令时,检查哪些迁移未执行
3. 按时间顺序执行未执行的迁移
4. 记录到 SequelizeMeta 表
5. 完成!

3. 迁移历史追踪

-- SequelizeMeta 表内容
+-------------------------------------+
| name                                |
+-------------------------------------+
| 20240219065551-init-users.js        |
| 20240219071334-add-platform.js      |
| 20240219074827-update-struct.js     |
+-------------------------------------+

🔄 迁移的完整生命周期

1. 创建迁移文件

# 你的 package.json 中已有命令
npm run generate-migration -- --name=add-email-field# 会生成类似这样的文件
# 20251007120000-add-email-field.js

2. 编写迁移内容

注意: Sequelize 不支持根据 Model 自动生成迁移内容

很多人误以为迁移会根据 Model 自动生成,但 Sequelize 官方不支持这个功能

其他 ORM 的对比:

// ❌ Sequelize - 不支持自动生成
npx sequelize migration:generate  // 只生成空模板// ✅ TypeORM - 支持自动生成
npm run typeorm migration:generate  // 会对比 Entity 和数据库,自动生成迁移// ✅ Django - 支持自动生成
python manage.py makemigrations  // 会对比 Model 和数据库,自动生成迁移// ✅ Prisma - 支持自动生成
npx prisma migrate dev  // 会对比 schema 和数据库,自动生成迁移
module.exports = {up: async (queryInterface, Sequelize) => {// 创建表await queryInterface.createTable('orders', {id: {type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true},user_id: {type: Sequelize.INTEGER,allowNull: false},total_price: {type: Sequelize.DECIMAL(10, 2),allowNull: false},created_at: {type: Sequelize.DATE,defaultValue: Sequelize.NOW}});// 添加索引await queryInterface.addIndex('orders', ['user_id']);// 添加外键await queryInterface.addConstraint('orders', {fields: ['user_id'],type: 'foreign key',references: {table: 'users',field: 'id'}});},down: async (queryInterface, Sequelize) => {// 回滚:删除表await queryInterface.dropTable('orders');}
};

3. 执行迁移

# 你的项目中
npm run migrate# 等同于
npx sequelize db:migrate

4. 回滚迁移

# 回滚最后一次迁移
npm run migrate:undo# 等同于
npx sequelize db:migrate:undo# 回滚所有迁移
npx sequelize db:migrate:undo:all

📊 常见迁移操作

1. 创建表

up: async (queryInterface, Sequelize) => {await queryInterface.createTable('products', {id: {type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true},name: {type: Sequelize.STRING(100),allowNull: false},price: {type: Sequelize.DECIMAL(10, 2),allowNull: false}});
}

2. 添加字段

// 你的项目中就有这个例子
up: async (queryInterface, Sequelize) => {await queryInterface.addColumn('collections', 'platform', {type: Sequelize.STRING,allowNull: false,defaultValue: 'taobao'  // 最好加默认值});
}

3. 修改字段

up: async (queryInterface, Sequelize) => {await queryInterface.changeColumn('users', 'age', {type: Sequelize.INTEGER,allowNull: true});
}

4. 删除字段

up: async (queryInterface, Sequelize) => {await queryInterface.removeColumn('users', 'old_field');
}

5. 重命名字段

up: async (queryInterface, Sequelize) => {await queryInterface.renameColumn('users', 'username', 'user_name');
}

6. 添加索引

up: async (queryInterface, Sequelize) => {await queryInterface.addIndex('orders', ['user_id', 'created_at'], {name: 'orders_user_created_idx'});
}

7. 删除表

up: async (queryInterface, Sequelize) => {await queryInterface.dropTable('old_table');
}

🎯 迁移的最佳实践

✅ 好的迁移

  1. 总是写 down 方法
module.exports = {up: async (queryInterface, Sequelize) => {await queryInterface.addColumn('users', 'email', {type: Sequelize.STRING});},down: async (queryInterface, Sequelize) => {await queryInterface.removeColumn('users', 'email'); // ✅ 能回滚}
};
  1. 处理已有数据
up: async (queryInterface, Sequelize) => {// 先添加字段(允许 NULL)await queryInterface.addColumn('users', 'status', {type: Sequelize.STRING,allowNull: true});// 给已有数据设置默认值await queryInterface.sequelize.query(`UPDATE users SET status = 'active' WHERE status IS NULL`);// 再修改为 NOT NULLawait queryInterface.changeColumn('users', 'status', {type: Sequelize.STRING,allowNull: false});
}
  1. 使用事务(保证原子性)
up: async (queryInterface, Sequelize) => {const transaction = await queryInterface.sequelize.transaction();try {await queryInterface.addColumn('users', 'email', {type: Sequelize.STRING}, { transaction });await queryInterface.addIndex('users', ['email'], { transaction });await transaction.commit();} catch (err) {await transaction.rollback();throw err;}
}

🔧 你的项目配置

package.json 中的迁移命令

{"scripts": {"generate-migration": "npx sequelize migration:generate --name=update-database-struct","migrate": "npx sequelize db:migrate","migrate:undo": "npx sequelize db:migrate:undo"}
}

🌍 多环境管理

你的配置支持不同环境:

# 开发环境(默认)
NODE_ENV=development npm run migrate# 生产环境
NODE_ENV=production npm run migrate

两种数据库管理方式

方式 1️⃣: Model.sync()你现在用的
// app.js
await this.app.model.sync({ force: false });

工作原理:

1. 读取 Model 定义(如 user.js)↓
2. 自动生成 CREATE TABLE SQL↓
3. 对比数据库,如果表不存在就创建↓
4. ✅ 表自动创建完成!

特点:

  • 自动化:根据 Model 自动创建表
  • 方便:不需要写迁移文件
  • 开发快速:改 Model 就自动更新表
  • 危险force: true 会删除所有数据!
  • 不可控:不知道具体改了什么
  • 无历史:没有变更记录
  • 生产环境不推荐:可能导致数据丢失
方式 2️⃣: Migration(迁移)应该用的
# 1. 手动生成迁移文件(空模板)
npm run generate-migration -- --name=create-users# 2. 手动编写迁移内容
# 20251007-create-users.js
up: async (queryInterface, Sequelize) => {await queryInterface.createTable('users', {id: {type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true},username: {type: Sequelize.STRING(50),allowNull: true}// ... 手动定义所有字段});
}# 3. 执行迁移
npm run migrate

工作原理:

1. 开发者手动创建迁移文件↓
2. 开发者手动编写 SQL 操作(up/down)↓
3. 执行 npm run migrate↓
4. 记录到 SequelizeMeta 表↓
5. ✅ 可追溯、可回滚!

特点:

  • 可控:精确控制每个变更
  • 可追溯:所有变更都有记录
  • 可回滚:可以撤销变更
  • 团队协作:大家同步数据库结构
  • 生产环境安全:不会意外删除数据
  • 麻烦:需要手动编写迁移文件
  • 不自动:Model 改了,还要手动写迁移

📊 对比总结

特性sync()Migration
自动化✅ 自动根据 Model 创建表❌ 需手动编写
开发速度⚡ 快🐢 慢
生产环境❌ 危险✅ 安全
变更历史❌ 无记录✅ 完整记录
回滚❌ 不支持✅ 支持
团队协作⚠️ 困难✅ 容易
数据安全⚠️ 可能丢失✅ 安全

📊 迁移 vs 直接改表

❌ 直接改表(危险)

-- 直接在数据库执行 SQL
ALTER TABLE users ADD COLUMN email VARCHAR(100);问题:
- 其他开发者不知道
- 生产环境可能忘记执行
- 无法回滚
- 无法追溯历史

✅ 使用迁移(安全)

// 迁移文件
up: async (queryInterface, Sequelize) => {await queryInterface.addColumn('users', 'email', {type: Sequelize.STRING(100)});
}优势:
- ✅ 版本控制(Git)
- ✅ 团队同步
- ✅ 可回滚
- ✅ 可追溯
- ✅ 自动化部署

🚀 部署流程

# 1. 本地开发
npm run generate-migration -- --name=add-new-feature
# 编写迁移文件
npm run migrate  # 本地测试# 2. 提交代码
git add database/migrations/
git commit -m "feat: 添加新功能的数据库迁移"
git push# 3. 服务器部署
ssh production-server
cd /path/to/project
git pull
npm run migrate  # 执行迁移
pm2 restart app  # 重启应用

🎓 总结

数据库迁移是:

  • 📦 数据库结构的版本控制系统
  • 📝 记录所有结构变更的历史
  • 🔄 支持前进(up)和回滚(down)
  • 👥 让团队成员的数据库保持同步
  • 🚀 让部署过程可追溯、可重复

就像:

  • Git 管理代码的变更
  • Migration 管理数据库的变更
http://www.dtcms.com/a/453394.html

相关文章:

  • Channel 和 Flow 选择场景对比 (例子:不停发事件的场景)
  • 《Vuejs设计与实现》第 18 章(同构渲染)(下)
  • jsp网站开发大作业长春网站建设wang
  • 淄博网站建设网宽河北网站建设推广电话
  • Django ORM 详解
  • C语言模拟面向对象编程方法之多态
  • 温州市建设工程管理网站温州建设网站哪家好
  • 划时代的技术飞跃:OpenAI DevDay 2025 全面深度解读
  • 做网站的网页图片素材怎么找长春做网站哪家便宜
  • 计算机操作系统:操作系统的发展过程
  • 未来之窗昭和仙君 (十三) 对话框组件— 东方仙盟筑基期
  • 茶叶公司网站建设策划书制作展示型网站公司哪家好
  • 部门定制网站建设公司免费电子版个人简历模板
  • 佛山营销网站建设咨询网站统计分析平台
  • 【工具变量】上市公司气候风险数据集(2011-2023年)
  • nat outbound acl-number address-group group-index 概念及题目
  • 电商网站构建预算方案门户网站html
  • CICD工具选型指南,Jenkins vs Arbess哪一款更好用?
  • 做彩票网站怎么样济南正规网站制作怎么选择
  • C++ 模板、泛型与 auto 关键字
  • 游戏项目 多态练习 超级玛丽demo8
  • 外企 BI 工具选型:从合规到落地
  • 医疗知识普及网站开发网站建立教学
  • Spring Boot中使用线程池来优化程序执行的效率!笔记01
  • 东平网站制作哪家好上海做网站站优云一一十七
  • 玩转ClaudeCode:通过Excel-MCP实现数据清洗并写入Excel
  • LeetCode 2761. 和等于目标值的质数对
  • 网站建设工作落实情况网站买流量是怎么做的
  • 开源 C++ QT QML 开发(九)文件--文本和二进制
  • 添加最新的LSKNet遥感目标检测网络主干