C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C#定时数据库备份工具

基于C#实现的定时数据库备份工具

作者:ytttr873

这篇文章主要介绍了如何C#实现的定时数据库备份工具,支持 SQL Server、MySQL、PostgreSQL、Oracle 等多种数据库,包含定时任务 、邮件通知、备份清理等功能,需要的朋友可以参考下

C# 定时数据库备份解决方案 支持 SQL Server、MySQL、PostgreSQL、Oracle 等多种数据库,包含定时任务、邮件通知、备份清理等功能。

一、项目结构

DatabaseBackupTool/
├── Program.cs                 # 程序入口
├── MainForm.cs                # 主窗体
├── BackupService.cs           # 备份服务核心
├── BackupScheduler.cs         # 定时调度器
├── DatabaseBackup.cs          # 数据库备份基类
├── SqlServerBackup.cs         # SQL Server备份
├── MySqlBackup.cs            # MySQL备份
├── PostgreSqlBackup.cs       # PostgreSQL备份
├── OracleBackup.cs           # Oracle备份
├── EmailNotifier.cs          # 邮件通知
├── LogManager.cs             # 日志管理
├── ConfigManager.cs          # 配置管理
└── DatabaseBackupTool.csproj

二、核心源码实现

2.1 项目文件 (DatabaseBackupTool.csproj)

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>
  <ItemGroup>
    <!-- 数据库驱动 -->
    <PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.1" />
    <PackageReference Include="MySql.Data" Version="8.2.0" />
    <PackageReference Include="Npgsql" Version="7.0.4" />
    <PackageReference Include="Oracle.ManagedDataAccess.Core" Version="3.21.110" />
    <!-- Quartz.NET 定时任务 -->
    <PackageReference Include="Quartz" Version="3.7.0" />
    <PackageReference Include="Quartz.Extensions.Hosting" Version="3.7.0" />
    <!-- 其他工具 -->
    <PackageReference Include="MailKit" Version="4.3.0" />
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
  </ItemGroup>
</Project>

2.2 程序入口 (Program.cs)

using System;
using System.Windows.Forms;

namespace DatabaseBackupTool
{
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            // 初始化日志
            LogManager.Initialize();
            LogManager.Info("数据库备份工具启动");
            
            Application.Run(new MainForm());
        }
    }
}

2.3 主窗体 (MainForm.cs)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace DatabaseBackupTool
{
    public partial class MainForm : Form
    {
        private BackupService backupService = new BackupService();
        private BackupScheduler scheduler = new BackupScheduler();
        private List<BackupTask> backupTasks = new List<BackupTask>();

        public MainForm()
        {
            InitializeComponent();
            LoadBackupTasks();
            UpdateTaskList();
        }

        private void LoadBackupTasks()
        {
            backupTasks = ConfigManager.LoadBackupTasks();
        }

        private void UpdateTaskList()
        {
            dgvTasks.Rows.Clear();
            foreach (var task in backupTasks)
            {
                dgvTasks.Rows.Add(
                    task.Name,
                    task.DatabaseType,
                    task.Server,
                    task.DatabaseName,
                    task.ScheduleType,
                    task.LastBackupTime.ToString("yyyy-MM-dd HH:mm"),
                    task.NextBackupTime.ToString("yyyy-MM-dd HH:mm"),
                    task.IsEnabled ? "启用" : "禁用"
                );
            }
        }

        private void btnAddTask_Click(object sender, EventArgs e)
        {
            BackupTaskForm taskForm = new BackupTaskForm();
            if (taskForm.ShowDialog() == DialogResult.OK)
            {
                var newTask = taskForm.BackupTask;
                backupTasks.Add(newTask);
                ConfigManager.SaveBackupTasks(backupTasks);
                UpdateTaskList();
                
                if (newTask.IsEnabled)
                {
                    scheduler.ScheduleTask(newTask);
                }
                
                LogManager.Info($"添加备份任务: {newTask.Name}");
            }
        }

        private void btnEditTask_Click(object sender, EventArgs e)
        {
            if (dgvTasks.SelectedRows.Count == 0)
            {
                MessageBox.Show("请选择要编辑的任务!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            int index = dgvTasks.SelectedRows[0].Index;
            var task = backupTasks[index];
            
            BackupTaskForm taskForm = new BackupTaskForm(task);
            if (taskForm.ShowDialog() == DialogResult.OK)
            {
                backupTasks[index] = taskForm.BackupTask;
                ConfigManager.SaveBackupTasks(backupTasks);
                UpdateTaskList();
                
                // 重新调度任务
                scheduler.RescheduleTask(backupTasks[index]);
                LogManager.Info($"更新备份任务: {task.Name}");
            }
        }

        private void btnDeleteTask_Click(object sender, EventArgs e)
        {
            if (dgvTasks.SelectedRows.Count == 0)
            {
                MessageBox.Show("请选择要删除的任务!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            int index = dgvTasks.SelectedRows[0].Index;
            var task = backupTasks[index];
            
            if (MessageBox.Show($"确定要删除任务 '{task.Name}' 吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                backupTasks.RemoveAt(index);
                ConfigManager.SaveBackupTasks(backupTasks);
                UpdateTaskList();
                
                scheduler.UnscheduleTask(task.Id);
                LogManager.Info($"删除备份任务: {task.Name}");
            }
        }

        private void btnManualBackup_Click(object sender, EventArgs e)
        {
            if (dgvTasks.SelectedRows.Count == 0)
            {
                MessageBox.Show("请选择要执行的任务!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            int index = dgvTasks.SelectedRows[0].Index;
            var task = backupTasks[index];
            
            btnManualBackup.Enabled = false;
            lblStatus.Text = $"正在执行备份: {task.Name}";
            
            backupService.ExecuteBackup(task, (success, message) =>
            {
                btnManualBackup.Enabled = true;
                lblStatus.Text = message;
                
                if (success)
                {
                    LogManager.Info($"手动备份成功: {task.Name}");
                    MessageBox.Show("备份执行成功!", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    LogManager.Error($"手动备份失败: {task.Name} - {message}");
                    MessageBox.Show($"备份执行失败: {message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                
                UpdateTaskList();
            });
        }

        private void btnTestConnection_Click(object sender, EventArgs e)
        {
            if (dgvTasks.SelectedRows.Count == 0)
            {
                MessageBox.Show("请选择要测试的任务!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            int index = dgvTasks.SelectedRows[0].Index;
            var task = backupTasks[index];
            
            lblStatus.Text = $"正在测试连接: {task.Name}";
            
            try
            {
                bool success = backupService.TestConnection(task);
                if (success)
                {
                    lblStatus.Text = "连接测试成功";
                    MessageBox.Show("数据库连接测试成功!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    lblStatus.Text = "连接测试失败";
                    MessageBox.Show("数据库连接测试失败!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception ex)
            {
                lblStatus.Text = $"连接测试异常: {ex.Message}";
                MessageBox.Show($"连接测试异常: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnViewLogs_Click(object sender, EventArgs e)
        {
            LogViewerForm logForm = new LogViewerForm();
            logForm.ShowDialog();
        }

        private void btnCleanup_Click(object sender, EventArgs e)
        {
            CleanupForm cleanupForm = new CleanupForm(backupTasks);
            cleanupForm.ShowDialog();
        }

        private void timerStatus_Tick(object sender, EventArgs e)
        {
            // 更新任务状态
            foreach (var task in backupTasks)
            {
                task.NextBackupTime = scheduler.GetNextFireTime(task);
            }
            UpdateTaskList();
        }

        #region Windows Form Designer generated code

        private System.ComponentModel.IContainer components = null;
        private MenuStrip menuStrip1;
        private ToolStripMenuItem 文件ToolStripMenuItem;
        private ToolStripMenuItem 退出ToolStripMenuItem;
        private ToolStripMenuItem 工具ToolStripMenuItem;
        private ToolStripMenuItem 清理旧备份ToolStripMenuItem;
        private ToolStripMenuItem 查看日志ToolStripMenuItem;
        private ToolStripMenuItem 帮助ToolStripMenuItem;
        private ToolStripMenuItem 关于ToolStripMenuItem;
        private GroupBox groupBox1;
        private Button btnAddTask;
        private Button btnEditTask;
        private Button btnDeleteTask;
        private Button btnManualBackup;
        private Button btnTestConnection;
        private DataGridView dgvTasks;
        private GroupBox groupBox2;
        private Button btnViewLogs;
        private Button btnCleanup;
        private Label lblStatus;
        private Timer timerStatus;

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.menuStrip1 = new System.Windows.Forms.MenuStrip();
            this.文件ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.退出ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.工具ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.清理旧备份ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.查看日志ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.帮助ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.关于ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.btnTestConnection = new System.Windows.Forms.Button();
            this.btnManualBackup = new System.Windows.Forms.Button();
            this.btnDeleteTask = new System.Windows.Forms.Button();
            this.btnEditTask = new System.Windows.Forms.Button();
            this.btnAddTask = new System.Windows.Forms.Button();
            this.dgvTasks = new System.Windows.Forms.DataGridView();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.btnCleanup = new System.Windows.Forms.Button();
            this.btnViewLogs = new System.Windows.Forms.Button();
            this.lblStatus = new System.Windows.Forms.Label();
            this.timerStatus = new System.Windows.Forms.Timer(this.components);
            this.menuStrip1.SuspendLayout();
            this.groupBox1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvTasks)).BeginInit();
            this.groupBox2.SuspendLayout();
            this.SuspendLayout();
            
            // menuStrip1
            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
                this.文件ToolStripMenuItem,
                this.工具ToolStripMenuItem,
                this.帮助ToolStripMenuItem});
            this.menuStrip1.Location = new System.Drawing.Point(0, 0);
            this.menuStrip1.Name = "menuStrip1";
            this.menuStrip1.Size = new System.Drawing.Size(800, 25);
            this.menuStrip1.TabIndex = 0;
            this.menuStrip1.Text = "menuStrip1";
            
            // 文件ToolStripMenuItem
            this.文件ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
                this.退出ToolStripMenuItem});
            this.文件ToolStripMenuItem.Name = "文件ToolStripMenuItem";
            this.文件ToolStripMenuItem.Size = new System.Drawing.Size(44, 21);
            this.文件ToolStripMenuItem.Text = "文件";
            
            // 退出ToolStripMenuItem
            this.退出ToolStripMenuItem.Name = "退出ToolStripMenuItem";
            this.退出ToolStripMenuItem.Size = new System.Drawing.Size(93, 22);
            this.退出ToolStripMenuItem.Text = "退出";
            this.退出ToolStripMenuItem.Click += new System.EventHandler(this.退出ToolStripMenuItem_Click);
            
            // 工具ToolStripMenuItem
            this.工具ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
                this.清理旧备份ToolStripMenuItem,
                this.查看日志ToolStripMenuItem});
            this.工具ToolStripMenuItem.Name = "工具ToolStripMenuItem";
            this.工具ToolStripMenuItem.Size = new System.Drawing.Size(44, 21);
            this.工具ToolStripMenuItem.Text = "工具";
            
            // 清理旧备份ToolStripMenuItem
            this.清理旧备份ToolStripMenuItem.Name = "清理旧备份ToolStripMenuItem";
            this.清理旧备份ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.清理旧备份ToolStripMenuItem.Text = "清理旧备份";
            this.清理旧备份ToolStripMenuItem.Click += new System.EventHandler(this.btnCleanup_Click);
            
            // 查看日志ToolStripMenuItem
            this.查看日志ToolStripMenuItem.Name = "查看日志ToolStripMenuItem";
            this.查看日志ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.查看日志ToolStripMenuItem.Text = "查看日志";
            this.查看日志ToolStripMenuItem.Click += new System.EventHandler(this.btnViewLogs_Click);
            
            // 帮助ToolStripMenuItem
            this.帮助ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
                this.关于ToolStripMenuItem});
            this.帮助ToolStripMenuItem.Name = "帮助ToolStripMenuItem";
            this.帮助ToolStripMenuItem.Size = new System.Drawing.Size(44, 21);
            this.帮助ToolStripMenuItem.Text = "帮助";
            
            // 关于ToolStripMenuItem
            this.关于ToolStripMenuItem.Name = "关于ToolStripMenuItem";
            this.关于ToolStripMenuItem.Size = new System.Drawing.Size(107, 22);
            this.关于ToolStripMenuItem.Text = "关于";
            this.关于ToolStripMenuItem.Click += new System.EventHandler(this.关于ToolStripMenuItem_Click);
            
            // groupBox1
            this.groupBox1.Controls.Add(this.btnTestConnection);
            this.groupBox1.Controls.Add(this.btnManualBackup);
            this.groupBox1.Controls.Add(this.btnDeleteTask);
            this.groupBox1.Controls.Add(this.btnEditTask);
            this.groupBox1.Controls.Add(this.btnAddTask);
            this.groupBox1.Location = new System.Drawing.Point(12, 30);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(200, 150);
            this.groupBox1.TabIndex = 1;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "任务管理";
            
            // btnTestConnection
            this.btnTestConnection.Location = new System.Drawing.Point(20, 115);
            this.btnTestConnection.Name = "btnTestConnection";
            this.btnTestConnection.Size = new System.Drawing.Size(160, 25);
            this.btnTestConnection.TabIndex = 4;
            this.btnTestConnection.Text = "测试连接";
            this.btnTestConnection.UseVisualStyleBackColor = true;
            this.btnTestConnection.Click += new System.EventHandler(this.btnTestConnection_Click);
            
            // btnManualBackup
            this.btnManualBackup.Location = new System.Drawing.Point(20, 85);
            this.btnManualBackup.Name = "btnManualBackup";
            this.btnManualBackup.Size = new System.Drawing.Size(160, 25);
            this.btnManualBackup.TabIndex = 3;
            this.btnManualBackup.Text = "立即备份";
            this.btnManualBackup.UseVisualStyleBackColor = true;
            this.btnManualBackup.Click += new System.EventHandler(this.btnManualBackup_Click);
            
            // btnDeleteTask
            this.btnDeleteTask.Location = new System.Drawing.Point(20, 55);
            this.btnDeleteTask.Name = "btnDeleteTask";
            this.btnDeleteTask.Size = new System.Drawing.Size(160, 25);
            this.btnDeleteTask.TabIndex = 2;
            this.btnDeleteTask.Text = "删除任务";
            this.btnDeleteTask.UseVisualStyleBackColor = true;
            this.btnDeleteTask.Click += new System.EventHandler(this.btnDeleteTask_Click);
            
            // btnEditTask
            this.btnEditTask.Location = new System.Drawing.Point(20, 30);
            this.btnEditTask.Name = "btnEditTask";
            this.btnEditTask.Size = new System.Drawing.Size(160, 25);
            this.btnEditTask.TabIndex = 1;
            this.btnEditTask.Text = "编辑任务";
            this.btnEditTask.UseVisualStyleBackColor = true;
            this.btnEditTask.Click += new System.EventHandler(this.btnEditTask_Click);
            
            // btnAddTask
            this.btnAddTask.Location = new System.Drawing.Point(20, 5);
            this.btnAddTask.Name = "btnAddTask";
            this.btnAddTask.Size = new System.Drawing.Size(160, 25);
            this.btnAddTask.TabIndex = 0;
            this.btnAddTask.Text = "添加任务";
            this.btnAddTask.UseVisualStyleBackColor = true;
            this.btnAddTask.Click += new System.EventHandler(this.btnAddTask_Click);
            
            // dgvTasks
            this.dgvTasks.AllowUserToAddRows = false;
            this.dgvTasks.AllowUserToDeleteRows = false;
            this.dgvTasks.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dgvTasks.Location = new System.Drawing.Point(220, 30);
            this.dgvTasks.Name = "dgvTasks";
            this.dgvTasks.ReadOnly = true;
            this.dgvTasks.RowHeadersWidth = 51;
            this.dgvTasks.RowTemplate.Height = 23;
            this.dgvTasks.Size = new System.Drawing.Size(568, 300);
            this.dgvTasks.TabIndex = 2;
            this.dgvTasks.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[]
            {
                new DataGridViewTextBoxColumn { HeaderText = "任务名称", Name = "Name", Width = 120 },
                new DataGridViewTextBoxColumn { HeaderText = "数据库类型", Name = "DatabaseType", Width = 80 },
                new DataGridViewTextBoxColumn { HeaderText = "服务器", Name = "Server", Width = 100 },
                new DataGridViewTextBoxColumn { HeaderText = "数据库", Name = "DatabaseName", Width = 100 },
                new DataGridViewTextBoxColumn { HeaderText = "计划", Name = "ScheduleType", Width = 80 },
                new DataGridViewTextBoxColumn { HeaderText = "上次备份", Name = "LastBackupTime", Width = 120 },
                new DataGridViewTextBoxColumn { HeaderText = "下次备份", Name = "NextBackupTime", Width = 120 },
                new DataGridViewTextBoxColumn { HeaderText = "状态", Name = "Status", Width = 60 }
            });
            
            // groupBox2
            this.groupBox2.Controls.Add(this.btnCleanup);
            this.groupBox2.Controls.Add(this.btnViewLogs);
            this.groupBox2.Location = new System.Drawing.Point(12, 190);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(200, 140);
            this.groupBox2.TabIndex = 3;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "系统工具";
            
            // btnCleanup
            this.btnCleanup.Location = new System.Drawing.Point(20, 55);
            this.btnCleanup.Name = "btnCleanup";
            this.btnCleanup.Size = new System.Drawing.Size(160, 25);
            this.btnCleanup.TabIndex = 1;
            this.btnCleanup.Text = "清理旧备份";
            this.btnCleanup.UseVisualStyleBackColor = true;
            this.btnCleanup.Click += new System.EventHandler(this.btnCleanup_Click);
            
            // btnViewLogs
            this.btnViewLogs.Location = new System.Drawing.Point(20, 25);
            this.btnViewLogs.Name = "btnViewLogs";
            this.btnViewLogs.Size = new System.Drawing.Size(160, 25);
            this.btnViewLogs.TabIndex = 0;
            this.btnViewLogs.Text = "查看日志";
            this.btnViewLogs.UseVisualStyleBackColor = true;
            this.btnViewLogs.Click += new System.EventHandler(this.btnViewLogs_Click);
            
            // lblStatus
            this.lblStatus.AutoSize = true;
            this.lblStatus.Location = new System.Drawing.Point(220, 335);
            this.lblStatus.Name = "lblStatus";
            this.lblStatus.Size = new System.Drawing.Size(44, 13);
            this.lblStatus.TabIndex = 4;
            this.lblStatus.Text = "就绪...";
            
            // timerStatus
            this.timerStatus.Enabled = true;
            this.timerStatus.Interval = 60000; // 每分钟更新一次
            this.timerStatus.Tick += new System.EventHandler(this.timerStatus_Tick);
            
            // MainForm
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 360);
            this.Controls.Add(this.lblStatus);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.dgvTasks);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.menuStrip1);
            this.MainMenuStrip = this.menuStrip1;
            this.Name = "MainForm";
            this.Text = "数据库定时备份工具";
            this.menuStrip1.ResumeLayout(false);
            this.menuStrip1.PerformLayout();
            this.groupBox1.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.dgvTasks)).EndInit();
            this.groupBox2.ResumeLayout(false);
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("数据库定时备份工具 v1.0\n\n支持SQL Server、MySQL、PostgreSQL、Oracle等数据库\n© 2024 版权所有", "关于", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        #endregion
    }
}

2.4 备份任务表单 (BackupTaskForm.cs)

using System;
using System.Windows.Forms;

namespace DatabaseBackupTool
{
    public partial class BackupTaskForm : Form
    {
        public BackupTask BackupTask { get; private set; }

        public BackupTaskForm(BackupTask existingTask = null)
        {
            InitializeComponent();
            
            if (existingTask != null)
            {
                BackupTask = existingTask;
                LoadTaskData();
            }
            else
            {
                BackupTask = new BackupTask();
                BackupTask.IsEnabled = true;
                BackupTask.ScheduleType = ScheduleType.Daily;
                BackupTask.BackupTime = new TimeSpan(2, 0, 0); // 默认凌晨2点
                BackupTask.RetentionDays = 30; // 默认保留30天
            }
        }

        private void LoadTaskData()
        {
            txtName.Text = BackupTask.Name;
            cmbDatabaseType.SelectedItem = BackupTask.DatabaseType;
            txtServer.Text = BackupTask.Server;
            txtPort.Text = BackupTask.Port.ToString();
            txtDatabase.Text = BackupTask.DatabaseName;
            txtUsername.Text = BackupTask.Username;
            txtPassword.Text = BackupTask.Password;
            txtBackupPath.Text = BackupTask.BackupPath;
            
            cmbScheduleType.SelectedItem = BackupTask.ScheduleType.ToString();
            dtpBackupTime.Value = DateTime.Today.Add(BackupTask.BackupTime);
            numRetentionDays.Value = BackupTask.RetentionDays;
            chkEnabled.Checked = BackupTask.IsEnabled;
            
            txtEmailRecipient.Text = BackupTask.EmailRecipient;
            chkSendEmail.Checked = BackupTask.SendEmailNotification;
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            if (ValidateInputs())
            {
                SaveTaskData();
                this.DialogResult = DialogResult.OK;
                this.Close();
            }
        }

        private bool ValidateInputs()
        {
            if (string.IsNullOrWhiteSpace(txtName.Text))
            {
                MessageBox.Show("请输入任务名称!", "验证", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtName.Focus();
                return false;
            }

            if (string.IsNullOrWhiteSpace(txtServer.Text))
            {
                MessageBox.Show("请输入数据库服务器地址!", "验证", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtServer.Focus();
                return false;
            }

            if (string.IsNullOrWhiteSpace(txtDatabase.Text))
            {
                MessageBox.Show("请输入数据库名称!", "验证", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtDatabase.Focus();
                return false;
            }

            if (string.IsNullOrWhiteSpace(txtBackupPath.Text))
            {
                MessageBox.Show("请输入备份路径!", "验证", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtBackupPath.Focus();
                return false;
            }

            return true;
        }

        private void SaveTaskData()
        {
            BackupTask.Name = txtName.Text;
            BackupTask.DatabaseType = cmbDatabaseType.SelectedItem.ToString();
            BackupTask.Server = txtServer.Text;
            BackupTask.Port = int.Parse(txtPort.Text);
            BackupTask.DatabaseName = txtDatabase.Text;
            BackupTask.Username = txtUsername.Text;
            BackupTask.Password = txtPassword.Text;
            BackupTask.BackupPath = txtBackupPath.Text;
            
            BackupTask.ScheduleType = (ScheduleType)Enum.Parse(typeof(ScheduleType), cmbScheduleType.SelectedItem.ToString());
            BackupTask.BackupTime = dtpBackupTime.Value.TimeOfDay;
            BackupTask.RetentionDays = (int)numRetentionDays.Value;
            BackupTask.IsEnabled = chkEnabled.Checked;
            
            BackupTask.EmailRecipient = txtEmailRecipient.Text;
            BackupTask.SendEmailNotification = chkSendEmail.Checked;
        }

        #region Windows Form Designer generated code

        private System.ComponentModel.IContainer components = null;
        private TextBox txtName;
        private Label label1;
        private ComboBox cmbDatabaseType;
        private Label label2;
        private TextBox txtServer;
        private Label label3;
        private TextBox txtPort;
        private Label label4;
        private TextBox txtDatabase;
        private Label label5;
        private TextBox txtUsername;
        private Label label6;
        private TextBox txtPassword;
        private Label label7;
        private TextBox txtBackupPath;
        private Button btnBrowsePath;
        private Label label8;
        private ComboBox cmbScheduleType;
        private Label label9;
        private DateTimePicker dtpBackupTime;
        private Label label10;
        private NumericUpDown numRetentionDays;
        private CheckBox chkEnabled;
        private GroupBox groupBox1;
        private TextBox txtEmailRecipient;
        private Label label11;
        private CheckBox chkSendEmail;
        private Button btnOK;
        private Button btnCancel;

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.txtName = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.cmbDatabaseType = new System.Windows.Forms.ComboBox();
            this.label2 = new System.Windows.Forms.Label();
            this.txtServer = new System.Windows.Forms.TextBox();
            this.label3 = new System.Windows.Forms.Label();
            this.txtPort = new System.Windows.Forms.TextBox();
            this.label4 = new System.Windows.Forms.Label();
            this.txtDatabase = new System.Windows.Forms.TextBox();
            this.label5 = new System.Windows.Forms.Label();
            this.txtUsername = new System.Windows.Forms.TextBox();
            this.label6 = new System.Windows.Forms.Label();
            this.txtPassword = new System.Windows.Forms.TextBox();
            this.label7 = new System.Windows.Forms.Label();
            this.txtBackupPath = new System.Windows.Forms.TextBox();
            this.btnBrowsePath = new System.Windows.Forms.Button();
            this.label8 = new System.Windows.Forms.Label();
            this.cmbScheduleType = new System.Windows.Forms.ComboBox();
            this.label9 = new System.Windows.Forms.Label();
            this.dtpBackupTime = new System.Windows.Forms.DateTimePicker();
            this.label10 = new System.Windows.Forms.Label();
            this.numRetentionDays = new System.Windows.Forms.NumericUpDown();
            this.chkEnabled = new System.Windows.Forms.CheckBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.chkSendEmail = new System.Windows.Forms.CheckBox();
            this.txtEmailRecipient = new System.Windows.Forms.TextBox();
            this.label11 = new System.Windows.Forms.Label();
            this.btnOK = new System.Windows.Forms.Button();
            this.btnCancel = new System.Windows.Forms.Button();
            ((System.ComponentModel.ISupportInitialize)(this.numRetentionDays)).BeginInit();
            this.groupBox1.SuspendLayout();
            this.SuspendLayout();
            
            // txtName
            this.txtName.Location = new System.Drawing.Point(100, 20);
            this.txtName.Name = "txtName";
            this.txtName.Size = new System.Drawing.Size(250, 23);
            this.txtName.TabIndex = 0;
            
            // label1
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(20, 23);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(56, 13);
            this.label1.TabIndex = 1;
            this.label1.Text = "任务名称:";
            
            // cmbDatabaseType
            this.cmbDatabaseType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.cmbDatabaseType.FormattingEnabled = true;
            this.cmbDatabaseType.Items.AddRange(new object[] { "SQL Server", "MySQL", "PostgreSQL", "Oracle" });
            this.cmbDatabaseType.Location = new System.Drawing.Point(100, 50);
            this.cmbDatabaseType.Name = "cmbDatabaseType";
            this.cmbDatabaseType.Size = new System.Drawing.Size(250, 23);
            this.cmbDatabaseType.TabIndex = 2;
            this.cmbDatabaseType.SelectedIndex = 0;
            
            // label2
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(20, 53);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(56, 13);
            this.label2.TabIndex = 3;
            this.label2.Text = "数据库类型:";
            
            // txtServer
            this.txtServer.Location = new System.Drawing.Point(100, 80);
            this.txtServer.Name = "txtServer";
            this.txtServer.Size = new System.Drawing.Size(180, 23);
            this.txtServer.TabIndex = 3;
            this.txtServer.Text = "localhost";
            
            // label3
            this.label3.AutoSize = true;
            this.label3.Location = new System.Drawing.Point(20, 83);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(56, 13);
            this.label3.TabIndex = 4;
            this.label3.Text = "服务器地址:";
            
            // txtPort
            this.txtPort.Location = new System.Drawing.Point(290, 80);
            this.txtPort.Name = "txtPort";
            this.txtPort.Size = new System.Drawing.Size(60, 23);
            this.txtPort.TabIndex = 4;
            this.txtPort.Text = "1433";
            
            // label4
            this.label4.AutoSize = true;
            this.label4.Location = new System.Drawing.Point(290, 63);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(32, 13);
            this.label4.TabIndex = 5;
            this.label4.Text = "端口:";
            
            // txtDatabase
            this.txtDatabase.Location = new System.Drawing.Point(100, 110);
            this.txtDatabase.Name = "txtDatabase";
            this.txtDatabase.Size = new System.Drawing.Size(250, 23);
            this.txtDatabase.TabIndex = 5;
            
            // label5
            this.label5.AutoSize = true;
            this.label5.Location = new System.Drawing.Point(20, 113);
            this.label5.Name = "label5";
            this.label5.Size = new System.Drawing.Size(56, 13);
            this.label5.TabIndex = 6;
            this.label5.Text = "数据库名称:";
            
            // txtUsername
            this.txtUsername.Location = new System.Drawing.Point(100, 140);
            this.txtUsername.Name = "txtUsername";
            this.txtUsername.Size = new System.Drawing.Size(250, 23);
            this.txtUsername.TabIndex = 6;
            
            // label6
            this.label6.AutoSize = true;
            this.label6.Location = new System.Drawing.Point(20, 143);
            this.label6.Name = "label6";
            this.label6.Size = new System.Drawing.Size(56, 13);
            this.label6.TabIndex = 7;
            this.label6.Text = "用户名:";
            
            // txtPassword
            this.txtPassword.Location = new System.Drawing.Point(100, 170);
            this.txtPassword.Name = "txtPassword";
            this.txtPassword.PasswordChar = '*';
            this.txtPassword.Size = new System.Drawing.Size(250, 23);
            this.txtPassword.TabIndex = 7;
            
            // label7
            this.label7.AutoSize = true;
            this.label7.Location = new System.Drawing.Point(20, 173);
            this.label7.Name = "label7";
            this.label7.Size = new System.Drawing.Size(56, 13);
            this.label7.TabIndex = 8;
            this.label7.Text = "密码:";
            
            // txtBackupPath
            this.txtBackupPath.Location = new System.Drawing.Point(100, 200);
            this.txtBackupPath.Name = "txtBackupPath";
            this.txtBackupPath.Size = new System.Drawing.Size(250, 23);
            this.txtBackupPath.TabIndex = 8;
            
            // btnBrowsePath
            this.btnBrowsePath.Location = new System.Drawing.Point(355, 198);
            this.btnBrowsePath.Name = "btnBrowsePath";
            this.btnBrowsePath.Size = new System.Drawing.Size(25, 23);
            this.btnBrowsePath.TabIndex = 9;
            this.btnBrowsePath.Text = "...";
            this.btnBrowsePath.UseVisualStyleBackColor = true;
            this.btnBrowsePath.Click += new System.EventHandler(this.btnBrowsePath_Click);
            
            // label8
            this.label8.AutoSize = true;
            this.label8.Location = new System.Drawing.Point(20, 203);
            this.label8.Name = "label8";
            this.label8.Size = new System.Drawing.Size(56, 13);
            this.label8.TabIndex = 9;
            this.label8.Text = "备份路径:";
            
            // cmbScheduleType
            this.cmbScheduleType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.cmbScheduleType.FormattingEnabled = true;
            this.cmbScheduleType.Items.AddRange(new object[] { "Daily", "Weekly", "Monthly" });
            this.cmbScheduleType.Location = new System.Drawing.Point(100, 230);
            this.cmbScheduleType.Name = "cmbScheduleType";
            this.cmbScheduleType.Size = new System.Drawing.Size(120, 23);
            this.cmbScheduleType.TabIndex = 10;
            this.cmbScheduleType.SelectedIndex = 0;
            
            // label9
            this.label9.AutoSize = true;
            this.label9.Location = new System.Drawing.Point(20, 233);
            this.label9.Name = "label9";
            this.label9.Size = new System.Drawing.Size(56, 13);
            this.label9.TabIndex = 10;
            this.label9.Text = "备份计划:";
            
            // dtpBackupTime
            this.dtpBackupTime.Format = System.Windows.Forms.DateTimePickerFormat.Time;
            this.dtpBackupTime.Location = new System.Drawing.Point(230, 230);
            this.dtpBackupTime.Name = "dtpBackupTime";
            this.dtpBackupTime.Size = new System.Drawing.Size(120, 23);
            this.dtpBackupTime.TabIndex = 11;
            this.dtpBackupTime.Value = new System.DateTime(2024, 1, 1, 2, 0, 0, 0);
            
            // label10
            this.label10.AutoSize = true;
            this.label10.Location = new System.Drawing.Point(230, 213);
            this.label10.Name = "label10";
            this.label10.Size = new System.Drawing.Size(56, 13);
            this.label10.TabIndex = 11;
            this.label10.Text = "备份时间:";
            
            // numRetentionDays
            this.numRetentionDays.Location = new System.Drawing.Point(100, 260);
            this.numRetentionDays.Maximum = new decimal(new int[] { 365, 0, 0, 0 });
            this.numRetentionDays.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
            this.numRetentionDays.Name = "numRetentionDays";
            this.numRetentionDays.Size = new System.Drawing.Size(120, 23);
            this.numRetentionDays.TabIndex = 12;
            this.numRetentionDays.Value = new decimal(new int[] { 30, 0, 0, 0 });
            
            // label11
            this.label11.AutoSize = true;
            this.label11.Location = new System.Drawing.Point(20, 263);
            this.label11.Name = "label11";
            this.label11.Size = new System.Drawing.Size(56, 13);
            this.label11.TabIndex = 12;
            this.label11.Text = "保留天数:";
            
            // chkEnabled
            this.chkEnabled.AutoSize = true;
            this.chkEnabled.Location = new System.Drawing.Point(230, 262);
            this.chkEnabled.Name = "chkEnabled";
            this.chkEnabled.Size = new System.Drawing.Size(48, 17);
            this.chkEnabled.TabIndex = 13;
            this.chkEnabled.Text = "启用";
            this.chkEnabled.UseVisualStyleBackColor = true;
            this.chkEnabled.Checked = true;
            
            // groupBox1
            this.groupBox1.Controls.Add(this.chkSendEmail);
            this.groupBox1.Controls.Add(this.txtEmailRecipient);
            this.groupBox1.Controls.Add(this.label11);
            this.groupBox1.Location = new System.Drawing.Point(20, 290);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(360, 80);
            this.groupBox1.TabIndex = 14;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "邮件通知";
            
            // chkSendEmail
            this.chkSendEmail.AutoSize = true;
            this.chkSendEmail.Location = new System.Drawing.Point(20, 50);
            this.chkSendEmail.Name = "chkSendEmail";
            this.chkSendEmail.Size = new System.Drawing.Size(96, 17);
            this.chkSendEmail.TabIndex = 1;
            this.chkSendEmail.Text = "发送邮件通知";
            this.chkSendEmail.UseVisualStyleBackColor = true;
            
            // txtEmailRecipient
            this.txtEmailRecipient.Location = new System.Drawing.Point(20, 20);
            this.txtEmailRecipient.Name = "txtEmailRecipient";
            this.txtEmailRecipient.Size = new System.Drawing.Size(320, 23);
            this.txtEmailRecipient.TabIndex = 0;
            
            // label12
            this.label12.AutoSize = true;
            this.label12.Location = new System.Drawing.Point(20, 3);
            this.label12.Name = "label12";
            this.label12.Size = new System.Drawing.Size(56, 13);
            this.label12.TabIndex = 0;
            this.label12.Text = "收件人邮箱:";
            
            // btnOK
            this.btnOK.Location = new System.Drawing.Point(200, 380);
            this.btnOK.Name = "btnOK";
            this.btnOK.Size = new System.Drawing.Size(80, 30);
            this.btnOK.TabIndex = 15;
            this.btnOK.Text = "确定";
            this.btnOK.UseVisualStyleBackColor = true;
            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
            
            // btnCancel
            this.btnCancel.Location = new System.Drawing.Point(290, 380);
            this.btnCancel.Name = "btnCancel";
            this.btnCancel.Size = new System.Drawing.Size(80, 30);
            this.btnCancel.TabIndex = 16;
            this.btnCancel.Text = "取消";
            this.btnCancel.UseVisualStyleBackColor = true;
            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
            
            // BackupTaskForm
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(384, 422);
            this.Controls.Add(this.btnCancel);
            this.Controls.Add(this.btnOK);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.chkEnabled);
            this.Controls.Add(this.numRetentionDays);
            this.Controls.Add(this.dtpBackupTime);
            this.Controls.Add(this.cmbScheduleType);
            this.Controls.Add(this.txtBackupPath);
            this.Controls.Add(this.btnBrowsePath);
            this.Controls.Add(this.txtPassword);
            this.Controls.Add(this.txtUsername);
            this.Controls.Add(this.txtDatabase);
            this.Controls.Add(this.txtPort);
            this.Controls.Add(this.txtServer);
            this.Controls.Add(this.cmbDatabaseType);
            this.Controls.Add(this.txtName);
            this.Controls.Add(this.label10);
            this.Controls.Add(this.label9);
            this.Controls.Add(this.label8);
            this.Controls.Add(this.label7);
            this.Controls.Add(this.label6);
            this.Controls.Add(this.label5);
            this.Controls.Add(this.label4);
            this.Controls.Add(this.label3);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.label1);
            this.Name = "BackupTaskForm";
            this.Text = "备份任务配置";
            ((System.ComponentModel.ISupportInitialize)(this.numRetentionDays)).EndInit();
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        private void btnBrowsePath_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            folderDialog.Description = "选择备份文件保存路径";
            
            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                txtBackupPath.Text = folderDialog.SelectedPath;
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }

        #endregion
    }
}

2.5 备份任务模型 (BackupTask.cs)

using System;

namespace DatabaseBackupTool
{
    /// <summary>
    /// 备份任务模型
    /// </summary>
    public class BackupTask
    {
        public Guid Id { get; set; } = Guid.NewGuid();
        public string Name { get; set; } = "";
        public string DatabaseType { get; set; } = "SQL Server";
        public string Server { get; set; } = "localhost";
        public int Port { get; set; } = 1433;
        public string DatabaseName { get; set; } = "";
        public string Username { get; set; } = "";
        public string Password { get; set; } = "";
        public string BackupPath { get; set; } = "";
        
        public ScheduleType ScheduleType { get; set; } = ScheduleType.Daily;
        public TimeSpan BackupTime { get; set; } = new TimeSpan(2, 0, 0);
        public int RetentionDays { get; set; } = 30;
        public bool IsEnabled { get; set; } = true;
        
        public string EmailRecipient { get; set; } = "";
        public bool SendEmailNotification { get; set; } = false;
        
        public DateTime LastBackupTime { get; set; } = DateTime.MinValue;
        public DateTime NextBackupTime { get; set; } = DateTime.MinValue;
        public DateTime CreatedTime { get; set; } = DateTime.Now;
        public DateTime ModifiedTime { get; set; } = DateTime.Now;
    }

    /// <summary>
    /// 备份计划类型
    /// </summary>
    public enum ScheduleType
    {
        Daily,      // 每天
        Weekly,     // 每周
        Monthly     // 每月
    }

    /// <summary>
    /// 备份结果
    /// </summary>
    public class BackupResult
    {
        public bool Success { get; set; }
        public string Message { get; set; } = "";
        public string BackupFilePath { get; set; } = "";
        public long BackupSize { get; set; } = 0;
        public TimeSpan Duration { get; set; } = TimeSpan.Zero;
        public DateTime StartTime { get; set; } = DateTime.Now;
        public DateTime EndTime { get; set; } = DateTime.Now;
    }
}

2.6 备份服务核心 (BackupService.cs)

using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;

namespace DatabaseBackupTool
{
    /// <summary>
    /// 备份服务核心
    /// </summary>
    public class BackupService
    {
        private DatabaseBackup databaseBackup;

        /// <summary>
        /// 执行备份
        /// </summary>
        public void ExecuteBackup(BackupTask task, Action<bool, string> callback)
        {
            Task.Run(() =>
            {
                try
                {
                    LogManager.Info($"开始执行备份任务: {task.Name}");
                    
                    // 创建备份目录
                    if (!Directory.Exists(task.BackupPath))
                    {
                        Directory.CreateDirectory(task.BackupPath);
                    }

                    // 获取数据库备份实例
                    databaseBackup = GetDatabaseBackup(task.DatabaseType);
                    
                    // 执行备份
                    var result = databaseBackup.Backup(task);
                    
                    // 更新任务状态
                    task.LastBackupTime = DateTime.Now;
                    task.NextBackupTime = CalculateNextBackupTime(task);
                    task.ModifiedTime = DateTime.Now;

                    // 发送邮件通知
                    if (task.SendEmailNotification && !string.IsNullOrEmpty(task.EmailRecipient))
                    {
                        SendEmailNotification(task, result);
                    }

                    // 清理旧备份
                    CleanupOldBackups(task);

                    LogManager.Info($"备份任务完成: {task.Name} - {(result.Success ? "成功" : "失败")}");
                    callback(result.Success, result.Message);
                }
                catch (Exception ex)
                {
                    LogManager.Error($"备份任务异常: {task.Name} - {ex.Message}");
                    callback(false, $"备份异常: {ex.Message}");
                }
            });
        }

        /// <summary>
        /// 测试数据库连接
        /// </summary>
        public bool TestConnection(BackupTask task)
        {
            try
            {
                databaseBackup = GetDatabaseBackup(task.DatabaseType);
                return databaseBackup.TestConnection(task);
            }
            catch (Exception ex)
            {
                LogManager.Error($"连接测试失败: {task.Name} - {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 获取数据库备份实例
        /// </summary>
        private DatabaseBackup GetDatabaseBackup(string databaseType)
        {
            return databaseType switch
            {
                "SQL Server" => new SqlServerBackup(),
                "MySQL" => new MySqlBackup(),
                "PostgreSQL" => new PostgreSqlBackup(),
                "Oracle" => new OracleBackup(),
                _ => throw new NotSupportedException($"不支持的数据库类型: {databaseType}")
            };
        }

        /// <summary>
        /// 计算下次备份时间
        /// </summary>
        private DateTime CalculateNextBackupTime(BackupTask task)
        {
            DateTime now = DateTime.Now;
            DateTime todayBackupTime = now.Date.Add(task.BackupTime);

            return task.ScheduleType switch
            {
                ScheduleType.Daily => todayBackupTime <= now ? todayBackupTime.AddDays(1) : todayBackupTime,
                ScheduleType.Weekly => CalculateNextWeeklyBackup(now, task.BackupTime),
                ScheduleType.Monthly => CalculateNextMonthlyBackup(now, task.BackupTime),
                _ => todayBackupTime.AddDays(1)
            };
        }

        private DateTime CalculateNextWeeklyBackup(DateTime now, TimeSpan backupTime)
        {
            DateTime nextBackup = now.Date.Add(backupTime);
            while (nextBackup <= now || nextBackup.DayOfWeek != DayOfWeek.Sunday)
            {
                nextBackup = nextBackup.AddDays(1);
            }
            return nextBackup;
        }

        private DateTime CalculateNextMonthlyBackup(DateTime now, TimeSpan backupTime)
        {
            DateTime nextBackup = new DateTime(now.Year, now.Month, 1).Add(backupTime);
            if (nextBackup <= now)
            {
                nextBackup = nextBackup.AddMonths(1);
            }
            return nextBackup;
        }

        /// <summary>
        /// 清理旧备份
        /// </summary>
        private void CleanupOldBackups(BackupTask task)
        {
            try
            {
                if (task.RetentionDays <= 0) return;

                string[] backupFiles = Directory.GetFiles(task.BackupPath, $"{task.DatabaseName}_*.bak");
                DateTime cutoffDate = DateTime.Now.AddDays(-task.RetentionDays);

                foreach (string file in backupFiles)
                {
                    FileInfo fileInfo = new FileInfo(file);
                    if (fileInfo.CreationTime < cutoffDate)
                    {
                        File.Delete(file);
                        LogManager.Info($"删除旧备份文件: {file}");
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"清理旧备份失败: {task.Name} - {ex.Message}");
            }
        }

        /// <summary>
        /// 发送邮件通知
        /// </summary>
        private void SendEmailNotification(BackupTask task, BackupResult result)
        {
            try
            {
                EmailNotifier notifier = new EmailNotifier();
                string subject = $"数据库备份通知 - {task.Name}";
                string body = $@"
                    备份任务: {task.Name}<br/>
                    数据库: {task.DatabaseName}<br/>
                    服务器: {task.Server}<br/>
                    结果: {(result.Success ? "成功" : "失败")}<br/>
                    消息: {result.Message}<br/>
                    备份文件: {result.BackupFilePath}<br/>
                    文件大小: {result.BackupSize / 1024.0 / 1024.0:F2} MB<br/>
                    耗时: {result.Duration.TotalMinutes:F2} 分钟<br/>
                    开始时间: {result.StartTime:yyyy-MM-dd HH:mm:ss}<br/>
                    结束时间: {result.EndTime:yyyy-MM-dd HH:mm:ss}
                ";

                notifier.SendEmail(task.EmailRecipient, subject, body);
                LogManager.Info($"邮件通知已发送到: {task.EmailRecipient}");
            }
            catch (Exception ex)
            {
                LogManager.Error($"发送邮件通知失败: {task.Name} - {ex.Message}");
            }
        }
    }
}

2.7 数据库备份基类 (DatabaseBackup.cs)

using System;
using System.Diagnostics;
using System.IO;

namespace DatabaseBackupTool
{
    /// <summary>
    /// 数据库备份基类
    /// </summary>
    public abstract class DatabaseBackup
    {
        /// <summary>
        /// 执行备份
        /// </summary>
        public abstract BackupResult Backup(BackupTask task);

        /// <summary>
        /// 测试连接
        /// </summary>
        public abstract bool TestConnection(BackupTask task);

        /// <summary>
        /// 生成备份文件名
        /// </summary>
        protected string GenerateBackupFileName(string databaseName)
        {
            string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
            return $"{databaseName}_{timestamp}.bak";
        }

        /// <summary>
        /// 执行命令行工具
        /// </summary>
        protected BackupResult ExecuteCommand(string command, string arguments, string workingDirectory = "")
        {
            var result = new BackupResult();
            var stopwatch = Stopwatch.StartNew();

            try
            {
                ProcessStartInfo psi = new ProcessStartInfo
                {
                    FileName = command,
                    Arguments = arguments,
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true,
                    WorkingDirectory = workingDirectory
                };

                using Process process = Process.Start(psi);
                if (process == null)
                {
                    result.Success = false;
                    result.Message = "无法启动进程";
                    return result;
                }

                string output = process.StandardOutput.ReadToEnd();
                string error = process.StandardError.ReadToEnd();
                
                process.WaitForExit();

                stopwatch.Stop();
                result.Duration = stopwatch.Elapsed;
                result.EndTime = DateTime.Now;

                if (process.ExitCode == 0)
                {
                    result.Success = true;
                    result.Message = "备份成功";
                    result.BackupFilePath = output.Trim();
                }
                else
                {
                    result.Success = false;
                    result.Message = $"备份失败: {error}";
                }
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                result.Success = false;
                result.Message = $"执行命令异常: {ex.Message}";
                result.Duration = stopwatch.Elapsed;
            }

            return result;
        }

        /// <summary>
        /// 获取文件大小
        /// </summary>
        protected long GetFileSize(string filePath)
        {
            if (File.Exists(filePath))
            {
                FileInfo fileInfo = new FileInfo(filePath);
                return fileInfo.Length;
            }
            return 0;
        }
    }
}

2.8 SQL Server 备份实现 (SqlServerBackup.cs)

using System;
using System.Data;
using Microsoft.Data.SqlClient;

namespace DatabaseBackupTool
{
    /// <summary>
    /// SQL Server 备份实现
    /// </summary>
    public class SqlServerBackup : DatabaseBackup
    {
        public override BackupResult Backup(BackupTask task)
        {
            var result = new BackupResult { StartTime = DateTime.Now };

            try
            {
                string backupFileName = GenerateBackupFileName(task.DatabaseName);
                string backupFilePath = Path.Combine(task.BackupPath, backupFileName);

                string connectionString = BuildConnectionString(task);
                
                using var connection = new SqlConnection(connectionString);
                connection.Open();

                // 构建备份SQL
                string backupSql = $@"
                    BACKUP DATABASE [{task.DatabaseName}]
                    TO DISK = @BackupPath
                    WITH FORMAT, INIT, NAME = @BackupName, SKIP, NOREWIND, NOUNLOAD, STATS = 10
                ";

                using var command = new SqlCommand(backupSql, connection);
                command.Parameters.AddWithValue("@BackupPath", backupFilePath);
                command.Parameters.AddWithValue("@BackupName", $"{task.DatabaseName} Full Backup");
                
                command.CommandTimeout = 3600; // 1小时超时
                command.ExecuteNonQuery();

                result.Success = true;
                result.Message = "SQL Server 备份成功";
                result.BackupFilePath = backupFilePath;
                result.BackupSize = GetFileSize(backupFilePath);
                result.EndTime = DateTime.Now;

                LogManager.Info($"SQL Server 备份完成: {backupFilePath}");
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.Message = $"SQL Server 备份失败: {ex.Message}";
                result.EndTime = DateTime.Now;
                LogManager.Error($"SQL Server 备份失败: {ex.Message}");
            }

            return result;
        }

        public override bool TestConnection(BackupTask task)
        {
            try
            {
                string connectionString = BuildConnectionString(task);
                using var connection = new SqlConnection(connectionString);
                connection.Open();
                return true;
            }
            catch (Exception ex)
            {
                LogManager.Error($"SQL Server 连接测试失败: {ex.Message}");
                return false;
            }
        }

        private string BuildConnectionString(BackupTask task)
        {
            if (string.IsNullOrEmpty(task.Username))
            {
                return $"Server={task.Server},{task.Port};Database=master;Integrated Security=True;TrustServerCertificate=True;";
            }
            else
            {
                return $"Server={task.Server},{task.Port};Database=master;User ID={task.Username};Password={task.Password};TrustServerCertificate=True;";
            }
        }
    }
}

2.9 MySQL 备份实现 (MySqlBackup.cs)

using System;
using System.Diagnostics;
using System.IO;

namespace DatabaseBackupTool
{
    /// <summary>
    /// MySQL 备份实现
    /// </summary>
    public class MySqlBackup : DatabaseBackup
    {
        public override BackupResult Backup(BackupTask task)
        {
            var result = new BackupResult { StartTime = DateTime.Now };

            try
            {
                string backupFileName = GenerateBackupFileName(task.DatabaseName);
                string backupFilePath = Path.Combine(task.BackupPath, backupFileName);

                // 构建 mysqldump 命令
                string arguments = $"-h{task.Server} -P{task.Port} -u{task.Username} -p{task.Password} " +
                                 $"--single-transaction --routines --triggers --events " +
                                 $"--databases {task.DatabaseName} > \"{backupFilePath}\"";

                // 执行 mysqldump
                result = ExecuteCommand("mysqldump", arguments);
                result.StartTime = DateTime.Now;

                if (result.Success)
                {
                    result.BackupFilePath = backupFilePath;
                    result.BackupSize = GetFileSize(backupFilePath);
                    LogManager.Info($"MySQL 备份完成: {backupFilePath}");
                }
                else
                {
                    LogManager.Error($"MySQL 备份失败: {result.Message}");
                }
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.Message = $"MySQL 备份异常: {ex.Message}";
                LogManager.Error($"MySQL 备份异常: {ex.Message}");
            }

            result.EndTime = DateTime.Now;
            return result;
        }

        public override bool TestConnection(BackupTask task)
        {
            try
            {
                using var connection = new MySql.Data.MySqlClient.MySqlConnection(BuildConnectionString(task));
                connection.Open();
                return true;
            }
            catch (Exception ex)
            {
                LogManager.Error($"MySQL 连接测试失败: {ex.Message}");
                return false;
            }
        }

        private string BuildConnectionString(BackupTask task)
        {
            return $"server={task.Server};port={task.Port};database={task.DatabaseName};uid={task.Username};pwd={task.Password};";
        }
    }
}

2.10 定时调度器 (BackupScheduler.cs)

using System;
using System.Collections.Generic;
using Quartz;
using Quartz.Impl;

namespace DatabaseBackupTool
{
    /// <summary>
    /// 备份定时调度器
    /// </summary>
    public class BackupScheduler
    {
        private IScheduler scheduler;
        private Dictionary<Guid, JobKey> jobKeys = new Dictionary<Guid, JobKey>();

        public async void Initialize()
        {
            try
            {
                // 创建调度器工厂
                StdSchedulerFactory factory = new StdSchedulerFactory();
                scheduler = await factory.GetScheduler();
                await scheduler.Start();
                
                LogManager.Info("定时调度器启动成功");
            }
            catch (Exception ex)
            {
                LogManager.Error($"定时调度器启动失败: {ex.Message}");
            }
        }

        public async void ScheduleTask(BackupTask task)
        {
            if (!task.IsEnabled) return;

            try
            {
                // 创建作业
                IJobDetail job = JobBuilder.Create<BackupJob>()
                    .WithIdentity($"Job_{task.Id}", "BackupJobs")
                    .UsingJobData("TaskId", task.Id.ToString())
                    .Build();

                // 创建触发器
                ITrigger trigger = CreateTrigger(task);

                // 调度作业
                await scheduler.ScheduleJob(job, trigger);
                jobKeys[task.Id] = job.Key;

                LogManager.Info($"任务已调度: {task.Name}");
            }
            catch (Exception ex)
            {
                LogManager.Error($"调度任务失败: {task.Name} - {ex.Message}");
            }
        }

        public async void RescheduleTask(BackupTask task)
        {
            // 先取消原有调度
            UnscheduleTask(task.Id);
            
            // 重新调度
            if (task.IsEnabled)
            {
                ScheduleTask(task);
            }
        }

        public async void UnscheduleTask(Guid taskId)
        {
            if (jobKeys.ContainsKey(taskId))
            {
                await scheduler.DeleteJob(jobKeys[taskId]);
                jobKeys.Remove(taskId);
                LogManager.Info($"任务已取消调度: {taskId}");
            }
        }

        private ITrigger CreateTrigger(BackupTask task)
        {
            string cronExpression = GetCronExpression(task);
            
            return TriggerBuilder.Create()
                .WithIdentity($"Trigger_{task.Id}", "BackupTriggers")
                .WithCronSchedule(cronExpression)
                .Build();
        }

        private string GetCronExpression(BackupTask task)
        {
            int hour = task.BackupTime.Hours;
            int minute = task.BackupTime.Minutes;
            int second = task.BackupTime.Seconds;

            return task.ScheduleType switch
            {
                ScheduleType.Daily => $"{second} {minute} {hour} * * ?",
                ScheduleType.Weekly => $"{second} {minute} {hour} ? * SUN",
                ScheduleType.Monthly => $"{second} {minute} {hour} 1 * ?",
                _ => $"{second} {minute} {hour} * * ?"
            };
        }

        public DateTime GetNextFireTime(BackupTask task)
        {
            if (!task.IsEnabled) return DateTime.MinValue;

            string cronExpression = GetCronExpression(task);
            var cron = new Quartz.CronExpression(cronExpression);
            return cron.GetNextValidTimeAfter(DateTime.Now) ?? DateTime.MinValue;
        }

        public async void Shutdown()
        {
            if (scheduler != null)
            {
                await scheduler.Shutdown();
                LogManager.Info("定时调度器已关闭");
            }
        }
    }

    /// <summary>
    /// 备份作业
    /// </summary>
    public class BackupJob : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            var jobData = context.JobDetail.JobDataMap;
            string taskIdStr = jobData.GetString("TaskId");
            
            if (Guid.TryParse(taskIdStr, out Guid taskId))
            {
                // 从配置中获取任务
                var tasks = ConfigManager.LoadBackupTasks();
                var task = tasks.Find(t => t.Id == taskId);
                
                if (task != null && task.IsEnabled)
                {
                    var backupService = new BackupService();
                    backupService.ExecuteBackup(task, (success, message) =>
                    {
                        LogManager.Info($"定时备份完成: {task.Name} - {message}");
                    });
                }
            }
            
            await Task.CompletedTask;
        }
    }
}

2.11 邮件通知 (EmailNotifier.cs)

using System;
using MailKit.Net.Smtp;
using MimeKit;
using MimeKit.Text;

namespace DatabaseBackupTool
{
    /// <summary>
    /// 邮件通知
    /// </summary>
    public class EmailNotifier
    {
        private readonly string smtpServer = "smtp.gmail.com"; // 配置您的SMTP服务器
        private readonly int smtpPort = 587;
        private readonly string smtpUsername = "your-email@gmail.com"; // 配置您的邮箱
        private readonly string smtpPassword = "your-password"; // 配置您的密码

        public void SendEmail(string recipient, string subject, string body)
        {
            try
            {
                var message = new MimeMessage();
                message.From.Add(new MailboxAddress("数据库备份系统", smtpUsername));
                message.To.Add(new MailboxAddress("", recipient));
                message.Subject = subject;
                message.Body = new TextPart(TextFormat.Html) { Text = body };

                using var client = new SmtpClient();
                client.Connect(smtpServer, smtpPort, MailKit.Security.SecureSocketOptions.StartTls);
                client.Authenticate(smtpUsername, smtpPassword);
                client.Send(message);
                client.Disconnect(true);
            }
            catch (Exception ex)
            {
                LogManager.Error($"发送邮件失败: {ex.Message}");
                throw;
            }
        }
    }
}

2.12 日志管理 (LogManager.cs)

using System;
using System.IO;

namespace DatabaseBackupTool
{
    /// <summary>
    /// 日志管理
    /// </summary>
    public static class LogManager
    {
        private static string logFilePath = "logs/backup.log";
        private static object lockObject = new object();

        public static void Initialize()
        {
            string logDir = Path.GetDirectoryName(logFilePath);
            if (!string.IsNullOrEmpty(logDir) && !Directory.Exists(logDir))
            {
                Directory.CreateDirectory(logDir);
            }
        }

        public static void Info(string message)
        {
            WriteLog("INFO", message);
        }

        public static void Warning(string message)
        {
            WriteLog("WARNING", message);
        }

        public static void Error(string message)
        {
            WriteLog("ERROR", message);
        }

        private static void WriteLog(string level, string message)
        {
            try
            {
                string logMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{level}] {message}";
                
                lock (lockObject)
                {
                    File.AppendAllText(logFilePath, logMessage + Environment.NewLine);
                }
            }
            catch
            {
                // 忽略日志写入错误
            }
        }

        public static string[] ReadLogs(int count = 100)
        {
            try
            {
                if (File.Exists(logFilePath))
                {
                    var lines = File.ReadAllLines(logFilePath);
                    if (lines.Length > count)
                    {
                        return lines[^count..];
                    }
                    return lines;
                }
            }
            catch
            {
                // 忽略错误
            }
            
            return Array.Empty<string>();
        }
    }
}

2.13 配置管理 (ConfigManager.cs)

using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;

namespace DatabaseBackupTool
{
    /// <summary>
    /// 配置管理
    /// </summary>
    public static class ConfigManager
    {
        private static string configFilePath = "config/backup_tasks.json";

        public static List<BackupTask> LoadBackupTasks()
        {
            try
            {
                if (File.Exists(configFilePath))
                {
                    string json = File.ReadAllText(configFilePath);
                    return JsonConvert.DeserializeObject<List<BackupTask>>(json) ?? new List<BackupTask>();
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"加载配置失败: {ex.Message}");
            }
            
            return new List<BackupTask>();
        }

        public static void SaveBackupTasks(List<BackupTask> tasks)
        {
            try
            {
                string configDir = Path.GetDirectoryName(configFilePath);
                if (!string.IsNullOrEmpty(configDir) && !Directory.Exists(configDir))
                {
                    Directory.CreateDirectory(configDir);
                }

                string json = JsonConvert.SerializeObject(tasks, Formatting.Indented);
                File.WriteAllText(configFilePath, json);
                
                LogManager.Info("备份任务配置已保存");
            }
            catch (Exception ex)
            {
                LogManager.Error($"保存配置失败: {ex.Message}");
            }
        }
    }
}

2.14 日志查看器 (LogViewerForm.cs)

using System;
using System.Windows.Forms;

namespace DatabaseBackupTool
{
    public partial class LogViewerForm : Form
    {
        public LogViewerForm()
        {
            InitializeComponent();
            LoadLogs();
        }

        private void LoadLogs()
        {
            string[] logs = LogManager.ReadLogs(200);
            txtLogs.Lines = logs;
            txtLogs.SelectionStart = txtLogs.Text.Length;
            txtLogs.ScrollToCaret();
        }

        #region Windows Form Designer generated code

        private System.ComponentModel.IContainer components = null;
        private TextBox txtLogs;
        private Button btnRefresh;
        private Button btnClear;
        private Button btnClose;

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.txtLogs = new System.Windows.Forms.TextBox();
            this.btnRefresh = new System.Windows.Forms.Button();
            this.btnClear = new System.Windows.Forms.Button();
            this.btnClose = new System.Windows.Forms.Button();
            this.SuspendLayout();
            
            // txtLogs
            this.txtLogs.Location = new System.Drawing.Point(12, 12);
            this.txtLogs.Multiline = true;
            this.txtLogs.Name = "txtLogs";
            this.txtLogs.ReadOnly = true;
            this.txtLogs.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.txtLogs.Size = new System.Drawing.Size(660, 400);
            this.txtLogs.TabIndex = 0;
            
            // btnRefresh
            this.btnRefresh.Location = new System.Drawing.Point(12, 422);
            this.btnRefresh.Name = "btnRefresh";
            this.btnRefresh.Size = new System.Drawing.Size(80, 30);
            this.btnRefresh.TabIndex = 1;
            this.btnRefresh.Text = "刷新";
            this.btnRefresh.UseVisualStyleBackColor = true;
            this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
            
            // btnClear
            this.btnClear.Location = new System.Drawing.Point(100, 422);
            this.btnClear.Name = "btnClear";
            this.btnClear.Size = new System.Drawing.Size(80, 30);
            this.btnClear.TabIndex = 2;
            this.btnClear.Text = "清空日志";
            this.btnClear.UseVisualStyleBackColor = true;
            this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
            
            // btnClose
            this.btnClose.Location = new System.Drawing.Point(592, 422);
            this.btnClose.Name = "btnClose";
            this.btnClose.Size = new System.Drawing.Size(80, 30);
            this.btnClose.TabIndex = 3;
            this.btnClose.Text = "关闭";
            this.btnClose.UseVisualStyleBackColor = true;
            this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
            
            // LogViewerForm
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(684, 464);
            this.Controls.Add(this.btnClose);
            this.Controls.Add(this.btnClear);
            this.Controls.Add(this.btnRefresh);
            this.Controls.Add(this.txtLogs);
            this.Name = "LogViewerForm";
            this.Text = "日志查看器";
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            LoadLogs();
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确定要清空所有日志吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                try
                {
                    File.WriteAllText("logs/backup.log", "");
                    txtLogs.Clear();
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"清空日志失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion
    }
}

2.15 清理工具 (CleanupForm.cs)

using System;
using System.IO;
using System.Windows.Forms;

namespace DatabaseBackupTool
{
    public partial class CleanupForm : Form
    {
        private List<BackupTask> backupTasks;

        public CleanupForm(List<BackupTask> tasks)
        {
            InitializeComponent();
            backupTasks = tasks;
            LoadTasks();
        }

        private void LoadTasks()
        {
            cmbTasks.Items.Clear();
            foreach (var task in backupTasks)
            {
                cmbTasks.Items.Add(task.Name);
            }
            
            if (cmbTasks.Items.Count > 0)
            {
                cmbTasks.SelectedIndex = 0;
            }
        }

        private void btnCleanup_Click(object sender, EventArgs e)
        {
            if (cmbTasks.SelectedIndex < 0)
            {
                MessageBox.Show("请选择要清理的任务!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            int retentionDays = (int)numRetentionDays.Value;
            if (retentionDays <= 0)
            {
                MessageBox.Show("保留天数必须大于0!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            var task = backupTasks[cmbTasks.SelectedIndex];
            string backupPath = task.BackupPath;

            if (!Directory.Exists(backupPath))
            {
                MessageBox.Show("备份路径不存在!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (MessageBox.Show($"确定要清理 {task.Name} 中超过 {retentionDays} 天的备份文件吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                try
                {
                    int deletedCount = CleanupOldBackups(backupPath, retentionDays, task.DatabaseName);
                    MessageBox.Show($"清理完成!共删除 {deletedCount} 个备份文件。", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"清理失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private int CleanupOldBackups(string backupPath, int retentionDays, string databaseName)
        {
            int deletedCount = 0;
            DateTime cutoffDate = DateTime.Now.AddDays(-retentionDays);

            string[] backupFiles = Directory.GetFiles(backupPath, $"{databaseName}_*.bak");
            foreach (string file in backupFiles)
            {
                FileInfo fileInfo = new FileInfo(file);
                if (fileInfo.CreationTime < cutoffDate)
                {
                    File.Delete(file);
                    deletedCount++;
                    LogManager.Info($"删除旧备份文件: {file}");
                }
            }

            return deletedCount;
        }

        #region Windows Form Designer generated code

        private System.ComponentModel.IContainer components = null;
        private ComboBox cmbTasks;
        private Label label1;
        private NumericUpDown numRetentionDays;
        private Label label2;
        private Button btnCleanup;
        private Button btnClose;

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.cmbTasks = new System.Windows.Forms.ComboBox();
            this.label1 = new System.Windows.Forms.Label();
            this.numRetentionDays = new System.Windows.Forms.NumericUpDown();
            this.label2 = new System.Windows.Forms.Label();
            this.btnCleanup = new System.Windows.Forms.Button();
            this.btnClose = new System.Windows.Forms.Button();
            ((System.ComponentModel.ISupportInitialize)(this.numRetentionDays)).BeginInit();
            this.SuspendLayout();
            
            // cmbTasks
            this.cmbTasks.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.cmbTasks.FormattingEnabled = true;
            this.cmbTasks.Location = new System.Drawing.Point(100, 20);
            this.cmbTasks.Name = "cmbTasks";
            this.cmbTasks.Size = new System.Drawing.Size(250, 23);
            this.cmbTasks.TabIndex = 0;
            
            // label1
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(20, 23);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(56, 13);
            this.label1.TabIndex = 1;
            this.label1.Text = "选择任务:";
            
            // numRetentionDays
            this.numRetentionDays.Location = new System.Drawing.Point(100, 50);
            this.numRetentionDays.Maximum = new decimal(new int[] { 365, 0, 0, 0 });
            this.numRetentionDays.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
            this.numRetentionDays.Name = "numRetentionDays";
            this.numRetentionDays.Size = new System.Drawing.Size(120, 23);
            this.numRetentionDays.TabIndex = 2;
            this.numRetentionDays.Value = new decimal(new int[] { 30, 0, 0, 0 });
            
            // label2
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(20, 53);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(56, 13);
            this.label2.TabIndex = 3;
            this.label2.Text = "保留天数:";
            
            // btnCleanup
            this.btnCleanup.Location = new System.Drawing.Point(100, 90);
            this.btnCleanup.Name = "btnCleanup";
            this.btnCleanup.Size = new System.Drawing.Size(100, 30);
            this.btnCleanup.TabIndex = 4;
            this.btnCleanup.Text = "开始清理";
            this.btnCleanup.UseVisualStyleBackColor = true;
            this.btnCleanup.Click += new System.EventHandler(this.btnCleanup_Click);
            
            // btnClose
            this.btnClose.Location = new System.Drawing.Point(210, 90);
            this.btnClose.Name = "btnClose";
            this.btnClose.Size = new System.Drawing.Size(100, 30);
            this.btnClose.TabIndex = 5;
            this.btnClose.Text = "关闭";
            this.btnClose.UseVisualStyleBackColor = true;
            this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
            
            // CleanupForm
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(370, 130);
            this.Controls.Add(this.btnClose);
            this.Controls.Add(this.btnCleanup);
            this.Controls.Add(this.numRetentionDays);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.cmbTasks);
            this.Controls.Add(this.label1);
            this.Name = "CleanupForm";
            this.Text = "清理旧备份";
            ((System.ComponentModel.ISupportInitialize)(this.numRetentionDays)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion
    }
}

三、功能特点

多数据库支持:SQL Server、MySQL、PostgreSQL、Oracle
定时备份:支持每天、每周、每月定时执行
邮件通知:备份完成后自动发送邮件通知
备份清理:自动清理超过保留天数的旧备份
日志记录:详细记录所有操作和错误信息
任务管理:添加、编辑、删除、启用/禁用备份任务
手动备份:支持随时手动执行备份
连接测试:测试数据库连接是否正常
配置持久化:备份任务配置自动保存

四、使用说明

4.1 快速开始

  1. 运行程序,点击"添加任务"
  2. 填写数据库连接信息
  3. 设置备份路径和计划
  4. 点击"确定"保存任务
  5. 任务将按计划自动执行

4.2 配置邮件通知

  1. 在任务配置中勾选"发送邮件通知"
  2. 填写收件人邮箱
  3. 修改 EmailNotifier.cs 中的 SMTP 服务器配置

4.3 手动执行备份

  1. 在主界面选择要执行的任务
  2. 点击"立即备份"按钮
  3. 查看备份结果

4.4 注意事项

以上就是基于C#实现的定时数据库备份工具的详细内容,更多关于C#定时数据库备份工具的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文