.NET BackgroundWorker和SQLTransactions

时间:2010-10-21 18:20:44

标签: .net subsonic background transactionscope

在哪里可以找到信息或如何在BackgroundWorker线程中处理SQL Server事务?我的理解是,不应在“DoWork”事件中设置错误处理,并且错误在内部处理并传递给“RunWorkerCompleted”。

我目前正在使用SubSonic作为我的DAL,并通过BackGroundWorder线程传递一些冗长的插入和更新。我遇到的问题是,当出现故障时,没有任何东西可以回滚。我决定使用事务管理器,但无法找到有关使用BackgroundWorker线程的事务的信息。

1 个答案:

答案 0 :(得分:1)

使用TransactionScope进行交易非常简单。

  1. 创建一个新的TransactionScope(在使用块中可以解决)

  2. 创建一个新的Sql连接(如果你这样做,那么它将不起作用)

  3. 运行一些crud操作

  4. 完成交易

  5. ???

  6. PROFIT !!!

  7. 在亚音速方面,这是你必须要做的事情:

    using (var ts = new TransactionScope())
    using (new SubSonic.SharedDbConnectionScope())
    {
    
        DoSomethingWithYourData();
    
        ts.Complete();
    }
    

    这就是后台发生的事情:

    如果您创建新的TransactionScope,则会将静态属性Transaction.Current设置为您的事务。现在,如果您创建一个新的DbConnection,则连接本身会查看Transaction.Current是否为null并且是否为TransactionCompleted事件。

    如果在放置Connection之前调用ts.Complete(),则提交事务,否则将回滚事务,并在TransactionScopes Dispose()方法中抛出异常。

    SubSonic本身将为您执行的每个语句创建一个新的连接(没有错误,它来自设计)但对交易不实用。这就是SharedDbConnectionScope()存在的原因。它与TransactionScope的工作方式类似(如果新的AutomaticConnectionScope检测到当前有SharedDbConnectionScope(),则会使用它的连接。否则将创建一个新连接。

    顺便说一句,using语法只不过是:

    var obj = new ObjectThatImplementsIDisposable();
    try
    {
    
    }
    finally
    {
        obj.Dispose();
    }
    

    长话短说:如果您在线程或BackgroundWorker中运行它,它不会影响您的事务。但是,你应该记住,如果你使用SharedDbConnecionScope(),即使来自其他线程的查询也会使用它们,我不认为SqlClient库是线程安全的(但我可能是错的,但MySqlClient肯定不是。

    Conculstion:我会切换到TransactionScope,因为它易于使用,灵活,通用(如果你决定有一天用你的应用程序切换到mysql或oracle,你不必担心)

    首先阅读问题的第一部分: - 我认为让BackGroundWorker的DoWork方法抛出异常是一个糟糕的设计。但你可以使用这种方法:

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
             ExecuteATransaction()
        }
        catch (Exception ex)
        {
             RollBackTransaction();
             e.Result = ex;
        }
    }
    
    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Result && e.Result.GetType() == typeof(Exception))
           throw ((Exception)e.Result);
        else
           Console.WriteLine("Everything went better than expected ;-)");
    }