如何在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
相关产品推荐
相关产品推荐

