Skip to content

数据备份

ts
import * as nodemailer from 'nodemailer';
import * as OSS from 'ali-oss'; // 阿里云 OSS SDK
import * as fs from 'fs';
import * as path from 'path';
import * as dayjs from 'dayjs';
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import mysqldump from 'mysqldump';

@Injectable()
export class TasksService {
  private readonly logger = new Logger(TasksService.name);

  constructor() {}

  @Cron(CronExpression.EVERY_DAY_AT_1AM)
  async execByTime() {
    // 确保目录存在
    const directory = path.resolve(__dirname, '../../backSql');
    if (!fs.existsSync(directory)) {
      fs.mkdirSync(directory, { recursive: true });
    }

    // 生成 SQL 文件路径
    const sqlFileName = `${dayjs(Date.now()).format('YYYY年MM月DD日HH时mm分ss秒')}.sql`;
    const sqlFilePath = path.join(directory, sqlFileName);

    // 执行数据库备份
    this.logger.debug('开始备份数据库...');
    await mysqldump({
      connection: {
        host: '119.96.24.5',
        user: 'root',
        password: 'Xianyu@666',
        database: 'fast_pigeon_devops_test1',
      },
      dumpToFile: sqlFilePath,
    });
    this.logger.debug(`数据库备份完成,文件路径:${sqlFilePath}`);

    // 发送邮件
    await this.sendEmailWithAttachment(sqlFilePath);

    // 上传到 OSS
    await this.uploadToOSS(sqlFilePath, sqlFileName);
  }

  // 发送邮件
  private async sendEmailWithAttachment(filePath: string) {
    this.logger.debug('开始发送邮件...');

    const transporter = nodemailer.createTransport({
      host: 'smtp.163.com', // 邮件服务提供商的 SMTP 地址
      port: 465,
      secure: true, // 使用 SSL
      auth: {
        user: 'your_email@163.com', // 发件人邮箱
        pass: 'your_email_password', // 发件人邮箱授权码
      },
    });

    const mailOptions = {
      from: '"SQL备份系统" <your_email@163.com>', // 发件人
      to: 'recipient@example.com', // 收件人
      subject: '每日 SQL 备份', // 邮件主题
      text: '请查收附件中的 SQL 备份文件。', // 邮件正文
      attachments: [
        {
          filename: path.basename(filePath), // 附件名称
          path: filePath, // 附件路径
        },
      ],
    };

    try {
      await transporter.sendMail(mailOptions);
      this.logger.debug('邮件发送成功!');
    } catch (error) {
      this.logger.error('邮件发送失败:', error);
    }
  }

  // 上传到 OSS
  private async uploadToOSS(filePath: string, fileName: string) {
    this.logger.debug('开始上传到 OSS...');

    const client = new OSS({
      region: 'oss-cn-hangzhou', // 阿里云 OSS 区域
      accessKeyId: 'your_access_key_id', // 阿里云 Access Key ID
      accessKeySecret: 'your_access_key_secret', // 阿里云 Access Key Secret
      bucket: 'your_bucket_name', // OSS 存储桶名称
    });

    try {
      const result = await client.put(`backups/${fileName}`, filePath);
      this.logger.debug(`上传到 OSS 成功,访问地址:${result.url}`);
    } catch (error) {
      this.logger.error('上传到 OSS 失败:', error);
    }
  }
}

关键点说明

  1. 备份 SQL 文件
    • 使用 [mysqldump](vscode-file://vscode-app/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) 将数据库备份到本地文件。
  2. 发送邮件
    • 使用 nodemailer 发送邮件。
    • 配置 SMTP 服务(如 smtp.163.com)。
    • 将 SQL 文件作为附件发送。
  3. 上传到 OSS
    • 使用阿里云 OSS SDK 上传文件。
    • 配置 OSS 的 regionaccessKeyIdaccessKeySecretbucket
  4. 日志记录
    • 使用 [Logger](vscode-file://vscode-app/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) 记录备份、邮件发送和 OSS 上传的状态。

示例日志输出

[TasksService] 开始备份数据库... [TasksService] 数据库备份完成,文件路径:/path/to/backSql/2025年04月01日01时00分00秒.sql [TasksService] 开始发送邮件... [TasksService] 邮件发送成功! [TasksService] 开始上传到 OSS... [TasksService] 上传到 OSS 成功,访问地址:https://your_bucket_name.oss-cn-hangzhou.aliyuncs.com/backups/2025年04月01日01时00分00秒.sql

总结

  • 备份 SQL 文件:使用 [mysqldump](vscode-file://vscode-app/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/workbench.html) 将数据库备份到本地。
  • 发送邮件:使用 nodemailer 将 SQL 文件作为附件发送到指定邮箱。
  • 上传到 OSS:使用阿里云 OSS SDK 将 SQL 文件上传到云存储。
  • 定时任务:通过 @Cron 注解每天定时执行备份、发送邮件和上传操作。