建表初始化

前言

通常初始化数据库要建立很多表,特别在项目开发的时候表的格式可能会有些变动,这时候就需要封装对数据库建表初始化的方法,保留项目的sql脚本文件,然后每次需要重新建表,则执行建表初始化程序就行

快速开始

demo源码

https://github.com/ChenShenhai/koa2-note/blob/master/demo/mysql/

源码目录

  1. ├── index.js # 程序入口文件
  2. ├── node_modules/
  3. ├── package.json
  4. ├── sql # sql脚本文件目录
  5. ├── data.sql
  6. └── user.sql
  7. └── util # 工具代码
  8. ├── db.js # 封装的mysql模块方法
  9. ├── get-sql-content-map.js # 获取sql脚本文件内容
  10. ├── get-sql-map.js # 获取所有sql脚本文件
  11. └── walk-file.js # 遍历sql脚本文件

具体流程

  1. +---------------------------------------------------+
  2. | |
  3. | +-----------+ +-----------+ +-----------+ |
  4. | | | | | | | |
  5. | | | | | | | |
  6. | | | | | | | |
  7. | | | | | | | |
  8. +----------+ 遍历sql +---+ 解析所有sql +---+ 执行sql +------------>
  9. | | 目录下的 | | 文件脚本 | | 脚本 | |
  10. +----------+ sql文件 +---+ 内容 +---+ +------------>
  11. | | | | | | | |
  12. | | | | | | | |
  13. | | | | | | | |
  14. | | | | | | | |
  15. | +-----------+ +-----------+ +-----------+ |
  16. | |
  17. +---------------------------------------------------+

源码详解

数据库操作文件 ./util/db.js

  1. const mysql = require('mysql')
  2. const pool = mysql.createPool({
  3. host : '127.0.0.1',
  4. user : 'root',
  5. password : 'abc123',
  6. database : 'koa_demo'
  7. })
  8. let query = function( sql, values ) {
  9. return new Promise(( resolve, reject ) => {
  10. pool.getConnection(function(err, connection) {
  11. if (err) {
  12. reject( err )
  13. } else {
  14. connection.query(sql, values, ( err, rows) => {
  15. if ( err ) {
  16. reject( err )
  17. } else {
  18. resolve( rows )
  19. }
  20. connection.release()
  21. })
  22. }
  23. })
  24. })
  25. }
  26. module.exports = {
  27. query
  28. }

获取所有sql脚本内容 ./util/get-sql-content-map.js

  1. const fs = require('fs')
  2. const getSqlMap = require('./get-sql-map')
  3. let sqlContentMap = {}
  4. /**
  5. * 读取sql文件内容
  6. * @param {string} fileName 文件名称
  7. * @param {string} path 文件所在的路径
  8. * @return {string} 脚本文件内容
  9. */
  10. function getSqlContent( fileName, path ) {
  11. let content = fs.readFileSync( path, 'binary' )
  12. sqlContentMap[ fileName ] = content
  13. }
  14. /**
  15. * 封装所有sql文件脚本内容
  16. * @return {object}
  17. */
  18. function getSqlContentMap () {
  19. let sqlMap = getSqlMap()
  20. for( let key in sqlMap ) {
  21. getSqlContent( key, sqlMap[key] )
  22. }
  23. return sqlContentMap
  24. }
  25. module.exports = getSqlContentMap

获取sql目录详情 ./util/get-sql-map.js

  1. const fs = require('fs')
  2. const walkFile = require('./walk-file')
  3. /**
  4. * 获取sql目录下的文件目录数据
  5. * @return {object}
  6. */
  7. function getSqlMap () {
  8. let basePath = __dirname
  9. basePath = basePath.replace(/\\/g, '\/')
  10. let pathArr = basePath.split('\/')
  11. pathArr = pathArr.splice( 0, pathArr.length - 1 )
  12. basePath = pathArr.join('/') + '/sql/'
  13. let fileList = walkFile( basePath, 'sql' )
  14. return fileList
  15. }
  16. module.exports = getSqlMap

遍历目录操作 ./util/walk-file.js

  1. const fs = require('fs')
  2. /**
  3. * 遍历目录下的文件目录
  4. * @param {string} pathResolve 需进行遍历的目录路径
  5. * @param {string} mime 遍历文件的后缀名
  6. * @return {object} 返回遍历后的目录结果
  7. */
  8. const walkFile = function( pathResolve , mime ){
  9. let files = fs.readdirSync( pathResolve )
  10. let fileList = {}
  11. for( let [ i, item] of files.entries() ) {
  12. let itemArr = item.split('\.')
  13. let itemMime = ( itemArr.length > 1 ) ? itemArr[ itemArr.length - 1 ] : 'undefined'
  14. let keyName = item + ''
  15. if( mime === itemMime ) {
  16. fileList[ item ] = pathResolve + item
  17. }
  18. }
  19. return fileList
  20. }
  21. module.exports = walkFile

入口文件 ./index.js

  1. const fs = require('fs');
  2. const getSqlContentMap = require('./util/get-sql-content-map');
  3. const { query } = require('./util/db');
  4. // 打印脚本执行日志
  5. const eventLog = function( err , sqlFile, index ) {
  6. if( err ) {
  7. console.log(`[ERROR] sql脚本文件: ${sqlFile} ${index + 1}条脚本 执行失败 o(╯□╰)o !`)
  8. } else {
  9. console.log(`[SUCCESS] sql脚本文件: ${sqlFile} ${index + 1}条脚本 执行成功 O(∩_∩)O !`)
  10. }
  11. }
  12. // 获取所有sql脚本内容
  13. let sqlContentMap = getSqlContentMap()
  14. // 执行建表sql脚本
  15. const createAllTables = async () => {
  16. for( let key in sqlContentMap ) {
  17. let sqlShell = sqlContentMap[key]
  18. let sqlShellList = sqlShell.split(';')
  19. for ( let [ i, shell ] of sqlShellList.entries() ) {
  20. if ( shell.trim() ) {
  21. let result = await query( shell )
  22. if ( result.serverStatus * 1 === 2 ) {
  23. eventLog( null, key, i)
  24. } else {
  25. eventLog( true, key, i)
  26. }
  27. }
  28. }
  29. }
  30. console.log('sql脚本执行结束!')
  31. console.log('请按 ctrl + c 键退出!')
  32. }
  33. createAllTables()

sql脚本文件 ./sql/data.sql

  1. CREATE TABLE IF NOT EXISTS `data` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `data_info` json DEFAULT NULL,
  4. `create_time` varchar(20) DEFAULT NULL,
  5. `modified_time` varchar(20) DEFAULT NULL,
  6. `level` int(11) DEFAULT NULL,
  7. PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8

sql脚本文件 ./sql/user.sql

  1. CREATE TABLE IF NOT EXISTS `user` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `email` varchar(255) DEFAULT NULL,
  4. `password` varchar(255) DEFAULT NULL,
  5. `name` varchar(255) DEFAULT NULL,
  6. `nick` varchar(255) DEFAULT NULL,
  7. `detail_info` json DEFAULT NULL,
  8. `create_time` varchar(20) DEFAULT NULL,
  9. `modified_time` varchar(20) DEFAULT NULL,
  10. `level` int(11) DEFAULT NULL,
  11. PRIMARY KEY (`id`)
  12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  13. INSERT INTO `user` set email='1@example.com', password='123456';
  14. INSERT INTO `user` set email='2@example.com', password='123456';
  15. INSERT INTO `user` set email='3@example.com', password='123456';

效果

执行脚本

  1. node index.js

执行结果

mysql-init-result-01

查看数据库写入数据

mysql-init-result-01