Nodejs 实现 Mysql 数据库的全量备份的代码演示

前言

往常,我们自己开发的系统,通常由运维进行数据库的备份。但这一次,我开发的一个小东西是交给客户自己去使用的。给用户系统搞好之后,用户希望可以在管理后台进行数据库的备份操作。所以,我需要一个接口,来实现数据库的备份。

一开始,我希望使用 mysql 数据库自带的 mysqldump 命令来实现备份,然后用 node 调用系统命令来实现。原理上是没有问题的,实践过程中遇到一些小的问题,就是 mysql 数据库的服务器和代码运行的服务器不是同一台服务器。

所以,可以不可以直接通过 SQL 语言来进行数据库的备份呢?虽然我作为一个前端,对于 SQL 肯定是不精通的。但是,借助 DeepSeek,我相信这个问题很好解决。

Mysql GUI 工具

完整代码演示

import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import * as mysql from 'mysql2/promise'

interface BackupConfig {
  host: string
  user: string
  password: string
  database: string
  outputDir?: string
}

export class MySQLBackup {
  private connection: mysql.Connection | null = null

  constructor(private config: BackupConfig) {
    this.config.outputDir = config.outputDir || './backups'
  }

  async connect() {
    this.connection = await mysql.createConnection({
      host: this.config.host,
      user: this.config.user,
      password: this.config.password,
      database: this.config.database,
    })
  }

  async getTableNames(): Promise<string[]> {
    const [rows] = await this.connection.query(
      `SELECT table_name FROM information_schema.tables 
       WHERE table_schema = ?`,
      [this.config.database],
    )
    return (rows as any[]).map((row) => row.TABLE_NAME)
  }

  async backupTable(table: string): Promise<string> {
    // 获取时区设置
    const [timezone] = await this.connection.query('SELECT @@session.time_zone AS tz')
    const tz = (timezone as any)[0].tz || '+00:00'

    // 获取建表语句
    const [createTable] = await this.connection.query(`SHOW CREATE TABLE \`${table}\``)

    // 获取数据并格式化为标准SQL
    const [rows] = await this.connection.query(`SELECT * FROM \`${table}\``)

    let sql = `SET time_zone = '${tz}';\n\n`
    sql += `-- DROP TABLE IF EXISTS \`${table}\`;\n`
    sql += `${(createTable as any)[0]['Create Table']};\n\n`

    if ((rows as any[]).length > 0) {
      sql += `INSERT INTO \`${table}\` VALUES\n`
      sql += `${(rows as any[])
        .map((row) => {
          const values = Object.values(row)
            .map((v) => {
              if (v === null) return 'NULL'
              if (v instanceof Date) {
                // 使用时区修正后的本地时间
                const adjustedDate = new Date(v.getTime() - v.getTimezoneOffset() * 60000)
                return `'${adjustedDate.toISOString().slice(0, 19).replace('T', ' ')}'`
              }
              if (typeof v === 'string') return mysql.escape(v)
              return v
            })
            .join(',')
          return `(${values})`
        })
        .join(',\n')};\n\n`
    }

    return sql
  }

  async fullBackup() {
    try {
      await fs.mkdir(this.config.outputDir, { recursive: true })
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
      const backupFile = path.join(this.config.outputDir, `backup_${timestamp}.sql`)

      const tables = await this.getTableNames()
      let backupContent = `-- MySQL Backup\n-- Database: ${this.config.database}\n-- Timestamp: ${timestamp}\n\n`

      for (const table of tables) {
        backupContent += await this.backupTable(table)
      }

      await fs.writeFile(backupFile, backupContent)
      console.log(`Backup saved to: ${backupFile}`)
    } catch (error) {
      console.error('Backup failed:', error)
    } finally {
      if (this.connection) await this.connection.end()
    }
  }
}

export default MySQLBackup

// 使用示例
// ;(async () => {
//   const backup = new MySQLBackup({
//     host: 'localhost',
//     user: 'root',
//     password: 'yourpassword',
//     database: 'your_database',
//   })

//   await backup.connect()
//   await backup.fullBackup()
// })()

小结

DeepSeek 提供的第一版代码直接报错,在告诉 DeepSeek 出错在哪里之后,新给了调整后的代码,终于顺利的备份了数据库了。

但是,我拿备份的 SQL 文件进行导入时发现,其在处理特殊字符和日期格式上出现了问题,于是,把问题再次交给 DeepSeek,又优化了一版本,这一次,终于备份成功,并且导入成功了。

在数据库导入成功之后,我仔细检查数据是否有异常,结果很快发现了异常,就是,数据库中的时间,和原始数据的时间,之间差了8个小时。很显然,这是 DeepSeek 没有考虑时区导致的。

于是,再次给 DeepSeek 讲,关于时区的问题,最终给出了以上代码,我实测,成功备份数据库,并顺利导入新数据库,仔细看数据,没有再发现新的问题。

其中 backupTable 函数,我基本不太理解,如果还有优化空间,或者BUG修复,欢迎各位看官在评论中留言交流。


最后,这种数据库备份的代码,只能用于数据库内容不大的小项目,如果数据库内容较多,还是很不合适的。那种情况,交给运维去处理或者借助云服务商的备份工具会更合理。

好,看到最后了,各位看官点个赞吧!谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值