You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中实现MySQL事务与File.Copy的原子性操作?

实现MySQL插入与文件复制的原子性操作

你的核心需求是让数据库插入和文件复制成为原子操作——要么两者都成功,要么都不生效。关键思路是:把文件复制放在事务提交之前执行,这样一旦复制失败,我们可以回滚数据库的插入操作;如果数据库插入先失败,直接终止流程,不会触发文件复制。

下面是修改后的完整代码,已经把File.Copy集成到事务逻辑中:

public void RunAtomicFileAndDbOperation()
{
    // 用using包裹连接,确保自动释放资源
    using (var conn = new MySqlConnection(ConnectionString.ConnString))
    {
        conn.Open();
        MySqlTransaction transaction = null;
        try
        {
            // 开启本地事务
            transaction = conn.BeginTransaction();
            
            using (var cmd = conn.CreateCommand())
            {
                cmd.Transaction = transaction;
                cmd.CommandText = @"INSERT INTO files 
                                    (document_name, path, version, section, user_modified, date_modified, review_date)
                                    VALUES (@doc, @path, @version, @section, @user, NOW(), NOW() + interval 12 month);";
                
                // 绑定参数,复用目标路径变量避免重复拼接
                var targetFilePath = $"{finalPath}Section {Section.Text}\\{docName.Text}{Path.GetExtension(fileName)}";
                cmd.Parameters.AddWithValue("@doc", docName.Text);
                cmd.Parameters.AddWithValue("@path", targetFilePath);
                cmd.Parameters.AddWithValue("@version", versionNumber.Text);
                cmd.Parameters.AddWithValue("@section", Section.Text);
                cmd.Parameters.AddWithValue("@user", UserDetails.userId);
                
                // 执行插入(此时数据仅在事务中,未持久化到数据库)
                cmd.ExecuteNonQuery();
            }
            
            // 执行文件复制——放在事务提交之前,确保复制失败可回滚数据库操作
            File.Copy(fileName, targetFilePath);
            
            // 只有文件复制成功,才提交事务,完成数据库插入
            transaction.Commit();
            MessageBox.Show("操作成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch (MySqlException dbEx)
        {
            // 数据库操作失败,回滚事务
            transaction?.Rollback();
            MessageBox.Show($"数据库操作失败:{dbEx.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
        catch (IOException fileEx)
        {
            // 文件复制失败,回滚已执行的数据库插入
            transaction?.Rollback();
            MessageBox.Show($"文件复制失败:{fileEx.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
        catch (Exception ex)
        {
            // 其他未知异常,同样回滚事务
            transaction?.Rollback();
            MessageBox.Show($"操作失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
        finally
        {
            conn.Close();
        }
    }
}

关键细节说明:

  • 事务执行顺序:先执行数据库插入但不提交,再执行文件复制。只有复制成功才提交事务,确保两者状态一致;任何一步失败都回滚到初始状态。
  • 资源安全:用using包裹数据库连接和命令,即使发生异常也能自动释放资源,避免连接泄漏。
  • 精准异常处理:分类捕获数据库和文件操作异常,能给用户更清晰的错误提示。
  • 代码复用:提取目标文件路径为变量,减少重复代码,降低出错概率。

这样就能完全满足你的需求:

  • 如果MySQL查询失败,直接终止流程,不执行任何文件操作
  • 如果MySQL查询成功但文件复制失败,自动回滚数据库插入,恢复到初始状态

内容的提问来源于stack exchange,提问作者HowdyCowboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 21:27:29