Sequelize是Nodejs生態中一個比較出名的ORM框架。經過ORM框架,可使用對象來操做數據庫表數據,提升了開發效率和代碼可讀性,也方便後期維護。
今天主要介紹經過遷移[Migration]
來建立數據庫,表。node
遷移的好處,能夠類比git。經過每次建立遷移文件,來支持更新,回滾數據庫表結構,也方便協同開發,也避免人工手動去直接修改數據庫,用代碼自動管理。換個電腦,也不用去拷貝數據庫,直接運行遷移就能夠徹底恢復開發環境,極大減輕了心智負擔。mysql
mkdir node_work cd node_work mkdir app npm init -y npm i sequelize-cli sequelize mysql2 koa
npx sequelize init
運行以後,會產生四個目錄:git
config, migrations, models, seederssql
config:數據庫
{ "development": { "username": "root", "password": "root", "database": "app_development", "host": "127.0.0.1", "port": 8889, "dialect": "mysql", "timezone": "+08:00" }, "test": { "username": "root", "password": null, "database": "app_test", "host": "127.0.0.1", "dialect": "mysql" }, "production": { "username": "root", "password": null, "database": "app_production", "host": "127.0.0.1", "dialect": "mysql" } }
環境env => {配置}
不一樣環境,對應不一樣的配置,也能夠自定義環境,好比homenpm
env指的是process.env.NODE_ENV
,json
能夠經過設置環境變量來改變,好比export NODE_ENV=production
;promise
遷移時候,也能夠指定環境:npx sequelize db:migrate --env production
,來鏈接production對應配置的數據庫cookie
建立數據庫:session
npx sequelize db:create
說明
npx
是npm5.2以後,自帶的一個命令。能夠不用全局安裝sequelize,使用時候,若是本地沒有,就去npm倉庫下載;下載完後或者本地已經下載過,就運行腳本命令。這樣能夠避免本地全局包過時,環境問題,每次都使用最新版本
migrations: 遷移文件
npx sequelize model:generate --name User --attributes username:string
執行後,會生成20180918055558-create-user.js
遷移文件,和models/user.js
模型文件
其餘字段能夠在遷移文件中補全,最後再運行npx sequelize db:migrate
,就能夠在數據庫中看到生成了users表
'use strict'; module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.createTable('Users', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: Sequelize.INTEGER }, username: { type: Sequelize.STRING(20), allowNull: false }, password: { type: Sequelize.CHAR(32), allowNull: false }, createdAt: { allowNull: false, type: Sequelize.DATE }, updatedAt: { allowNull: false, type: Sequelize.DATE } }, { tableName: 'users', charset: 'utf8mb4', collate: 'utf8mb4_bin', define: { timestamps: true } }).then(() => { // 添加索引 return queryInterface.addIndex('users', { name: 'username', unique: true, fields: ['username'] }); }); }, // 回退時執行,刪除表 down: (queryInterface, Sequelize) => { return queryInterface.dropTable('Users'); } };
執行遷移:
npx sequelize db:migrate npx sequelize db:migrate:all
撤銷遷移:
npx sequelize db:migrate:undo 最近一次的 npx sequelize db:migrate:undo:all npx sequelize db:migrate:undo:all --to XXXXXXXXXXXXXX-create-posts.js
--from, --to
參數,能夠指定遷移文件
models: 模型文件
model:generate
生成的model都在這個目錄中
'use strict'; module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.createTable('Users', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: Sequelize.INTEGER }, username: { type: Sequelize.STRING(20), allowNull: false }, password: { type: Sequelize.CHAR(32), allowNull: false }, createdAt: { allowNull: false, type: Sequelize.DATE }, updatedAt: { allowNull: false, type: Sequelize.DATE } }, { tableName: 'users', charset: 'utf8mb4', collate: 'utf8mb4_bin', }).then(() => { return queryInterface.addIndex('users', { name: 'username', unique: true, fields: ['username'] }); }); }, down: (queryInterface, Sequelize) => { return queryInterface.dropTable('Users'); } };
模型對象建立,默認會自動賦值,更新createdAt, updatedAt兩個timestamps字段。下邊會給出完整示例。
seeders: 填充數據文件
建立seed文件:
npx sequelize seed:generate --name demo-user
執行以後,會獲得20180918090545-demo-user.js
'use strict'; const md5 = require('md5') module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.bulkInsert('Users', [ { username: 'Kimoo', password: md5('123456'), createdAt: new Date(), updatedAt: new Date(), }, { username: 'Reci', password: md5('123321'), createdAt: new Date(), updatedAt: new Date(), } ], {}); }, down: (queryInterface, Sequelize) => { /* Add reverting commands here. Return a promise to correctly handle asynchronicity. Example: return queryInterface.bulkDelete('Person', null, {}); */ return queryInterface.bulkDelete('Users', null, {}); } };
填充數據:
npx sequelize db:seed:all
撤銷數據:
npx sequelize db:seed:undo 最近一次的 npx sequelize db:seed:undo --seed name-of-seed-as-in-data 具體某個 npx sequelize db:seed:undo:all
app.js
(async function() { const Koa = require('koa'); const KoaStaticCache = require('koa-static-cache'); const KoaBodyParser = require('koa-bodyparser'); const router = require('./routers/main'); const Session = require('koa-session'); const app = new Koa(); // app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256'); app.keys = ['app']; app.use( Session({ key: 'koa:sess', maxAge: 86400000, autoCommit: true, overwrite: true, httpOnly: true, signed: true, rolling: false, renew: false }, app) ); // app.use( async (ctx, next) => { // ctx.set('Access-Control-Allow-Origin','*'); // await next(); // } ); app.use( KoaStaticCache('./public', { prefix: 'public', gzip: true }) ); app.use( KoaBodyParser() ); app.use( router.routes() ); app.listen(8088); })();
models/index.js
'use strict'; const fs = require('fs'); const path = require('path'); const Sequelize = require('sequelize'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; const config = require(__dirname + '/../config/config.json')[env]; const db = {}; let sequelize; if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); } else { sequelize = new Sequelize(config.database, config.username, config.password, config); } // 自動導入 models 文件夾下的全部文件,好比user.js這個模型文件 // 自動加載模型並執行 // let users = require('./users'); // let UsersModel = users(sequelize, Sequelize); // db[UsersModel.name] = UsersModel; // db['Users'] = UsersModel; // 下面經過fs自動加載全部的文件,並執行,同時生成的模型對象掛載到db對象下面,最後返回出去 fs .readdirSync(__dirname) .filter(file => { return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); }) .forEach(file => { const model = sequelize['import'](path.join(__dirname, file)); db[model.name] = model; }); Object.keys(db).forEach(modelName => { if (db[modelName].associate) { db[modelName].associate(db); } }); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
routers/main.js
const KoaRouter = require('koa-router'); const md5 = require('md5'); const Models = require('../models'); const Sequelize = require('sequelize'); const router = new KoaRouter(); router.post('/register', async ctx => { // console.log(ctx.request.body); let username = ctx.request.body.username.trim(); let password = ctx.request.body.password.trim(); let repassword = ctx.request.body.repassword.trim(); if (username=='' || password == '' || repassword == '') { return ctx.body = { code: 1, data: '用戶名或密碼不能爲空' } } if (password != repassword) { return ctx.body = { code: 2, data: '兩次輸入的密碼不一致' } } let user = await Models.Users.findOne({ where: { username } }); if (user !== null) { return ctx.body = { code: 3, data: '當前用戶已經被註冊了' } } let newUser = await Models.Users.build({ username, password: md5(password) }).save(); ctx.body = { code: 0, data: { id: newUser.get('id'), username: newUser.get('username') } } }); router.post('/login', async ctx => { let username = ctx.request.body.username; let password = ctx.request.body.password; let user = await Models.Users.findOne({ where: { username } }); if (user === null) { return ctx.body = { code: 1, data: '不存在該用戶' } } if (user.get('password') !== md5(password)) { return ctx.body = { code: 1, data: '密碼錯誤' } } // ctx.cookies.set('uid', user.get('id'), { // httpOnly: false // }); // 服務端發送一個約定好的cookie,來表示當前是登陸 // ctx.cookies.set('uid', user.get('id'), { // // httpOnly,表示當前的cookie是否容許客戶端進行操做(js),若是爲true,那麼就表示這個cookie是能用戶http協議的數據傳輸 // httpOnly: true, // signed: true // }); ctx.cookies.set('username', user.get('username'), { httpOnly: false }); ctx.session.uid = 1; ctx.body = { code: 0, data: { id: user.get('id'), username: user.get('username') } } }); }) module.exports = router;
能夠在postman
中測試接口,地址http://localhost:8088/register
,註冊用戶
node app.js