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

如何为IO文件存储实现带自动回滚的自定义事务机制?

通用文件存储事务回滚实现方案

问题背景

现有文件存储接口及基础使用代码如下:

public interface IFileStorage
{
    void Save(string key);
    void Delete(string key);
}
var fileStorage = new FileStorage();
var files = new List<string>();

foreach(var file in files)
{
    fileStorage.Save(file);
}

当前实现存在缺陷:如果循环执行中途程序崩溃,已保存的文件会残留,没有回滚机制。我们需要实现一种类似事务的通用解决方案,通过using块包裹操作,一旦范围内发生错误,自动删除已保存的文件完成回滚,目标使用形式如下:

using (var transaction = new CustomFileStorageTransaction())
{
    var fileStorage = new FileStorage();
    var files = new List<string>();

    foreach (var file in files)
    {
        fileStorage.Save(file);
    }
}

解决方案实现

1. 事务核心类实现

基于IDisposable特性,在using块结束时自动判断是否需要回滚,同时追踪事务内保存的所有文件key:

public class CustomFileStorageTransaction : IDisposable
{
    private readonly List<string> _savedKeys = new List<string>();
    private bool _isCommitted = false;

    // 注册已成功保存的文件key
    public void TrackSavedKey(string key)
    {
        if (!_isCommitted)
        {
            _savedKeys.Add(key);
        }
    }

    // 手动提交事务:所有操作完成后调用,跳过后续回滚逻辑
    public void Commit()
    {
        _isCommitted = true;
        _savedKeys.Clear();
    }

    public void Dispose()
    {
        if (!_isCommitted)
        {
            // 执行回滚:删除所有已保存的文件
            using var storage = new FileStorage();
            foreach (var key in _savedKeys)
            {
                try
                {
                    storage.Delete(key);
                }
                catch (Exception ex)
                {
                    // 记录回滚异常,避免单个文件失败导致全部回滚中断
                    Console.WriteLine($"回滚文件 {key} 失败: {ex.Message}");
                }
            }
        }
    }
}

2. 装饰器包装原存储实现

用装饰器模式包裹IFileStorage,无需修改原FileStorage代码,自动将保存的key注册到事务中:

public class TransactionalFileStorage : IFileStorage
{
    private readonly IFileStorage _innerStorage;
    private readonly CustomFileStorageTransaction _transaction;

    public TransactionalFileStorage(IFileStorage innerStorage, CustomFileStorageTransaction transaction)
    {
        _innerStorage = innerStorage;
        _transaction = transaction;
    }

    public void Save(string key)
    {
        _innerStorage.Save(key);
        _transaction.TrackSavedKey(key);
    }

    public void Delete(string key)
    {
        _innerStorage.Delete(key);
    }
}

3. 最终使用示例

using (var transaction = new CustomFileStorageTransaction())
{
    var fileStorage = new TransactionalFileStorage(new FileStorage(), transaction);
    var files = new List<string> { "doc1.pdf", "photo2.jpg", "data3.csv" };

    try
    {
        foreach (var file in files)
        {
            fileStorage.Save(file);
            // 模拟中途出错场景
            if (file == "photo2.jpg")
            {
                throw new IOException("保存文件时发生IO错误");
            }
        }
        // 所有操作无异常,提交事务
        transaction.Commit();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"操作失败: {ex.Message}");
        // 无需手动回滚,using块结束时会自动执行
    }
}

方案优势

  • 通用性强:基于装饰器和事务类的组合,不侵入原FileStorage实现,符合开闭原则。
  • 自动回滚:利用IDisposable的特性,using块结束时自动处理回滚逻辑,无需手动编写try/catch重复代码。
  • 可靠性高:回滚时单个文件删除失败不影响其他文件,同时保留异常记录便于排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 06:50:23