【问题标题】:Transactional operations simultaneously mixed with non-transactional ones事务性操作同时与非事务性操作混合
【发布时间】:2013-01-12 13:20:58
【问题描述】:

我需要将数据从外部源导入到我的数据库。因为要下载的数据很多,导入执行时间很长,我需要将当前导入状态的定期更新持久化到数据库中(供用户关注)。

假设我有 2 个表:Import(导入数据的存储)和Status(导入状态监控表)。

数据导入代码:

public class Importer
{
    public delegate void ImportHandler(string item);
    public event ImportHandler ImportStarted;

    public void OnStart(string item)
    {            
        ImportStarted(item);
    }

    public void Execute(string[] items)
    {
        foreach (var item  in items)
        {
            OnStart(item);                    
            PersistImportedData(Download(item));
        }
    }

    private void PersistImportedData(object data)
    {
        using (var connection = new SqlConnection()){ /*saving imported data*/ }
    }
}

启动代码 - 用于调用导入任务并更新其状态:

public class Starter
{
    public void Process(string[] items)
    {
       var importer = new Importer();
       importer.ImportStarted += UpdateImportState;
       importer.Execute(items);
    }

    private void UpdateImportState(string item)
    {
        using (var connection = new SqlConnection()){ /*status updates*/ }
    }
}

现在一切正常。随着导入的进行,导入正在执行,用户正在获取状态更新(来自Status 表)。

出现问题是因为这样的逻辑不安全。我必须确定,导入是一个原子操作。我不想部分下载和保存数据。我已使用事务方法作为解决方案(我已将 importer.ExecuteTransactionScope 包装在一起):

importer.ImportStarted += UpdateImportState;
using (var scope = new TransactionScope())
{
    importer.Execute(items);
    scope.Complete();
}

现在我有了安全性 - 回滚发生,例如在进程中止的情况下。

我现在面临不同的问题 - 我想要解决的问题。我需要用户显示状态更新信息,但Status 表不受更新影响,而事务尚未完成。即使我尝试使用RequiresNew 选项来创建单独的事务(不是环境事务),也没有任何变化。 Execute 函数创建自己的数据库连接,UpdateImportState 也这样做。连接不共享。我不知道为什么State table 不会受到影响,即使TransactionScope 仅涵盖与Import table 连接的逻辑。

如何保持一致的导入并允许定期状态更新?

【问题讨论】:

  • 这个answer 上的 TransactionScope 行为可能很有用。

标签: c# .net sql-server-2008 transactions transactionscope


【解决方案1】:

在 UpdateImportState 中使用 TransactionScopeOption.Suppress 而不是 TransactionScopeOption.RequiresNew

【讨论】:

  • 范围必须保持在importer.Execute() 附近,因为它需要是原子工作单元。事实上,Suppress 添加到 UpdateImportState 的新范围选项解决了这个问题。顺便说一句:您知道为什么带有RequiresNew 选项的范围会阻止外部逻辑影响数据库吗?我认为它会创建新事务并忘记其他地方的情况(分离当前事务)。看起来外部逻辑现在必须使用 Suppress 选项标记新范围。
猜你喜欢
  • 2010-12-08
  • 1970-01-01
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 2018-03-18
  • 2018-07-13
  • 2023-03-04
  • 1970-01-01
相关资源
最近更新 更多