此文已由作者左裕初授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验
db migrate这种数据库管理的方式正在被移植到各种各样的语言和框架。据我所知,db migrate的思想最早由Ruby On Rails引入,所以熟知Ruby On Rails的同学基本可以忽略这篇文章(除非对db migrate思想的nodejs实现有浓厚兴趣),但是如果你是第一次接触它,它真的很有用。
很多情况下,我们开发有一个本地的环境,一个测试环境,一个正式的环境。本地若是多几个分支,而每个分支都要对数据库进行修改(如加一列,加一表)的话,就会凸显出数据库管理上的麻烦。更麻烦的是,一般来说,只有代码会放到代码仓库里头,数据库的不一致,常常会导致程序员:“它在我这儿是好的啊”。
问题的本质在于要同步数据库的结构(而非数据本身)。事实上db migrate不过是借鉴了版本管理方面的思想。举例来说,我们进行两步的操作,第一步建立一个user表,第二步,为username建个唯一索引。
所以对于第一个版本来说,执行这个版本的操作就是createTable,而回退这个操作则是dropTable。
对于第二个版本来说,它建立在第一个版本的基础上,执行这个版本的操作是createIndex,而回退这个操作则是dropIndex。
我确实接触过不少项目是拿SQL直接做数据库版本管理的,甚至是一些企业软件,拿着一堆SQL找客户更是家常便饭。之所以推荐DB migrate,个人觉得有如下原因:
程序语言支持的功能远比shell脚本+SQL的方案要多,“错误处理+回滚”套装拿shell+sql写起来很不方便,当需要执行一些“要么成功要么什么都不做”的操作的时候,程序语言比直接写SQL轻量太多。
多数据库支持,考虑到各个数据库的细微差别,db migrate可以把细节隐藏到驱动当中。(让我回想起为SQL Server和DB2各写一份脚本的岁月。。。)
多操作系统支持。win跟unix的shell各写一份也不是什么新闻了。
大部分语言都提供了db migrate思想的实现。我采用了nodejs的sequelize。原因如下,
比起Ruby,在国内,nodejs更好装。
nodejs的包管理更胜一筹
通过一个package.json,可以描述做db migrate的所有依赖。通常来说,一个sequelize, sequlize-cli,加上一个数据库驱动(如mysql),便可以完成以上的操作了。
mkdir migration-show && cd migration-show
npm install --save sequelize sequelize-cli mysql
./node_modules/sequelize-cli/bin/sequelize init:migrations # 初始化Migration文件夹
./node_modules/sequelize-cli/bin/sequelize init:config # 初始化配置文件
此时目录结构
.
├── config
│ └── config.json
├── migrations
├── node_modules
│ ├── mysql
│ ├── sequelize
│ └── sequelize-cli
└── package.json
config指定了用于测试,开发,部署的mysql配置,migrations正是存储了数据库变化的脚本
修改配置文件config/config.json,配置正确的服务器域名端口密码,然后创建migrations脚本
./node_modules/sequelize-cli/bin/sequelize migration:create
migrations文件夹中即多出一个Migration文件
.
├── config
│ └── config.json
├── migrations
│ └── 20160104204428-unnamed-migration.js
├── node_modules
│ ├── mysql
│ ├── sequelize
│ └── sequelize-cli
└── package.json
用标准js语法修改migration文件创建users表,这个表里头有一列叫Id。
'use strict';
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.createTable('users', { id: Sequelize.INTEGER });
},
down: function (queryInterface, Sequelize) {
return queryInterface.dropTable('users');
}
};
注意到它既有up函数又有Down函数,只要这两个操作满足上述的状态机,就保证了数据库操作是可重复的。
最后执行DB Migrate看看结果
./node_modules/sequelize-cli/bin/sequelize db:migrate
可以看到数据库里头多了两个表
users表正如我们定义的一样,SequelizeMeta则记录了有哪些Migration已经进入了数据库。正是这个表,保证了每一个migration操作是幂等的(即无论操作多少次,结果都是一致的)。
mysql> show tables;
+------------------------+
| Tables_in_database_dev |
+------------------------+
| SequelizeMeta |
| users |
+------------------------+
2 rows in set (0.00 sec)
mysql> show columns from users;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
mysql> select * from SequelizeMeta;
+-------------------------------------+
| name |
+-------------------------------------+
| 20160104204428-unnamed-migration.js |
+-------------------------------------+
1 row in set (0.00 sec)
db migrate在数据库管理方面有重大作用,这个思想同时也可以用于软件升级,笔者曾经利用该思想做过企业软件升级。除了表结构,它同样可以对数据库中一些预定的数据进行管理。再者,对于up/drop的操作,也可以在里头实现数据备份功能,让开发者更加高枕无忧。
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。