数据库上线&迭代上线

上线是啥?迭代上线是啥?

数据库上线: 线上数据库的初始化, 其实就是/sql/init.sql的生成
数据库 迭代上线: 将开发环境的数据库变动同步至线上, 主要是 同步数据库结构 和 系统数据到 线上数据库

注意: 业务数据是不需要同步 到线上的。

数据库上线

方案1: 使用Navicat导出init.sql

WechatIMG68.png

方案2: 使用Javascript导出init.sql

package.json

  1. {
  2. "dependencies": {
  3. "dotenv": "16.0.2",
  4. "knex": "^1.0.1",
  5. "mysql": "^2.18.1",
  6. "mysqldump": "^3.2.0"
  7. },
  8. "scripts": {
  9. "dumpSql": "node ./dumpSql.js"
  10. }
  11. }

.env

  1. DB_HOST=127.0.0.1
  2. DB_PORT=3306
  3. DB_USER=root
  4. DB_PASSWORD=123456

dumpSql.js

  1. 'use strict';
  2. /**
  3. * - 如果使用code runner 运行, 则将env配置到 '../.env'
  4. * - 如果使用node xxx.js 运行, 则将env配置到 './jianghujs-script-util/.env'
  5. */
  6. require('dotenv').config();
  7. const mysqldump = require('mysqldump')
  8. const Knex = require('knex')
  9. const fs = require("fs");
  10. const path = require('path')
  11. const connection = {
  12. host: process.env.DB_HOST,
  13. port: process.env.DB_PORT,
  14. user: process.env.DB_USER,
  15. password: process.env.DB_PASSWORD,
  16. };
  17. /**
  18. * 导出 sql
  19. * @param database 数据库
  20. * @param noDataTables 不导出数据的表,如 log 相关表
  21. * @param clearFields 导出前清除的表的字段
  22. * @param sqlFile 导出文件
  23. * @param replace 关键字替换
  24. * @returns {Promise<void>}
  25. */
  26. async function dumpSql({ database, noDataTables, sqlFile, replace, isIgnoreAllBizTable, isIgnoreAllBizTableData }) {
  27. connection.database = database;
  28. const knex = Knex({
  29. client: 'mysql',
  30. connection,
  31. });
  32. const startTime = new Date().getTime();
  33. const res = await mysqldump({
  34. connection,
  35. dump: {
  36. data: {
  37. format: false
  38. },
  39. schema: {
  40. table: {
  41. dropIfExist: true,
  42. },
  43. },
  44. trigger: {
  45. dropIfExist: false,
  46. },
  47. }
  48. });
  49. let content = '';
  50. res.tables.forEach(tableData => {
  51. if (isIgnoreAllBizTable && !tableData.name.startsWith('_')) {
  52. return;
  53. }
  54. if (noDataTables.includes(tableData.name) || (isIgnoreAllBizTableData && !tableData.name.startsWith('_'))) {
  55. // content += tableData.schema + '\n' + (tableData.triggers && tableData.triggers.join('\n') || '') + '\n\n\n'
  56. content += tableData.schema + '\n\n\n'
  57. } else {
  58. // content += tableData.schema + '\n' + (tableData.data || '') + '\n' + (tableData.triggers && tableData.triggers.join('\n') || '') + '\n\n\n'
  59. content += tableData.schema + '\n' + (tableData.data || '') + '\n\n\n'
  60. }
  61. })
  62. replace.forEach((item) => {
  63. content = content.replace(new RegExp(/DROP TRIGGER IF EXISTS (\w*);/, 'g'), 'DROP TRIGGER IF EXISTS `$1`;')
  64. content = content.replace(new RegExp(item.key, 'g'), item.value)
  65. })
  66. // 干掉init.sql trigger的注释
  67. content = content.replace(new RegExp(/# ------------------------------------------------------------\n# TRIGGER DUMP FOR: .*?\n# ------------------------------------------------------------\n/, 'g'), "");
  68. content = content.replace(new RegExp(/# ------------------------------------------------------------\n# DATA DUMP FOR TABLE: .*?\n# ------------------------------------------------------------\n/, 'g'), "");
  69. fs.writeFileSync(sqlFile, content);
  70. const endTime = new Date().getTime();
  71. console.log(`导出${database}结束, useTime: ${(endTime - startTime) / 1000.00}/s, sqlFile: ${sqlFile}`)
  72. await knex.destroy();
  73. }
  74. // 不导出数据部分的表
  75. let noDataTables = [
  76. "_cache",
  77. "_resource_request_log",
  78. "_user_session",
  79. "_record_history",
  80. "duoxing_chat_session",
  81. "duoxing_message_history",
  82. "_file",
  83. "article_history",
  84. "_user"
  85. ];
  86. // 导出前清理表中的无用字段
  87. let replace = [
  88. // 前缀处理成模板
  89. // { key: 'jianghujs_demo_enterprise_', value: '{{dbPrefix}}'},
  90. // 抹掉 utf8 相关配置
  91. { key: ' COLLATE utf8mb4_bin', value: '' },
  92. { key: ' COLLATE utf8', value: '' },
  93. { key: ' COLLATE = utf8mb4_bin', value: '' },
  94. { key: ' COLLATE = utf8', value: '' },
  95. { key: ' DEFAULT CHARSET = utf8mb4_bin', value: '' },
  96. { key: ' DEFAULT CHARSET = utf8mb4', value: '' },
  97. { key: ' DEFAULT CHARSET = utf8', value: '' },
  98. { key: ' CHARACTER SET utf8mb4_bin', value: '' },
  99. { key: ' CHARACTER SET utf8mb4', value: '' },
  100. { key: ' CHARACTER SET utf8', value: '' },
  101. ];
  102. (async () => {
  103. const currentProjectDir = path.join(__dirname, '..');
  104. const projectList = [
  105. { database: 'my_basic', projectName: 'my-basic', isIgnoreAllBizTableData: true },
  106. ]
  107. for (const project of projectList) {
  108. const projectNoDataTables = project.projectNoDataTables || [];
  109. await dumpSql({
  110. database: project.database,
  111. sqlFile: `${currentProjectDir}/sql/init.${project.projectName}.sql`,
  112. noDataTables: [...noDataTables, ...projectNoDataTables],
  113. replace,
  114. isIgnoreAllBizTable: project.isIgnoreAllBizTable,
  115. isIgnoreAllBizTableData: project.isIgnoreAllBizTableData,
  116. });
  117. }
  118. })()

运行node ./dumpSql.js,脚本就会将init.sql导出来

注意:_user数据比较隐私, 所以你需要手动导入

  1. INSERT INTO `_user` (`id`, `userId`, `username`, `clearTextPassword`, `password`, `md5Salt`, `userStatus`, `userType`, `operation`, `operationByUserId`, `operationByUser`, `operationAt`) VALUES (1, 'admin', '系统管理员', '123456', '38d61d315e62546fe7f1013e31d42f57', 'Xs4JSZnhiwsR', 'active', NULL, 'insert', 'admin', '系统管理员', '2022-09-15T23:46:04+08:00');

数据库迭代上线

迭代上线我们 使用 navicat 的 结构同步数据同步功能
dataSync.png

注意⚠️:结构同步时 只需同步以下的选项:
dataSync3.png

注意⚠️:数据同步时只需同步某些系统配置表,同步时勾选如下(可以通过右键取消全选后再选中这些表):
dataSync2.png