.NET 后台工作程序和 SQLTransactions

发布于 2024-09-28 15:48:42 字数 259 浏览 6 评论 0原文

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

我目前使用 SubSonic 作为我的 DAL,并通过 BackGroundWorder 线程传递一些冗长的插入和更新我遇到的问题是,当出现故障时,我决定使用 transactionscope,但找不到有关使用 BackgroundWorker 线程的事务的信息。

Where can I find information or how can I handle SQL Server transactions in a BackgroundWorker thread? It's my understanding that error handling should not be set in the "DoWork" event and that the error is handled internally and passed to the 'RunWorkerCompleted".

I am currently using SubSonic as my DAL and passing some lengthy inserts and updates via a BackGroundWorder thread. The problem I have is that when something fails nothing is rolledback. I was deciding on using a transactionscope but couldn't find information on using transactions with a BackgroundWorker thread.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

嗫嚅 2024-10-05 15:48:42

使用 TransactionScope 进行事务非常简单。

  1. 创建一个新的 TransactionScope(最好在 using 块内)

  2. 创建一个新的 Sql 连接(如果您以相反的方式进行操作,则不会工作)

  3. 运行一些增删改查操作

  4. 完成事务

  5. ???

  6. 利润!!!

就亚音速而言,这是您必须做的:

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 绝对不是。

结论:我会切换到 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 ;-)");
}

Transaction with TransactionScope are pretty straightforward.

  1. Create a new TransactionScope (prefferable within a using block)

  2. Create a new Sql Connection (if you do it the other way round it won't work)

  3. Run some crud operations

  4. Complete the transaction

  5. ???

  6. PROFIT!!!

In the terms of subsonic this is what you have to do:

using (var ts = new TransactionScope())
using (new SubSonic.SharedDbConnectionScope())
{

    DoSomethingWithYourData();

    ts.Complete();
}

That's what happens in the background:

If you create a new TransactionScope, the static property Transaction.Current is set to your transaction. Now, if you create a new DbConnection, the connections itselfs looks if Transaction.Current is not null and suscribes to the TransactionCompleted event.

If you call ts.Complete() before the Connection is disposed, the transaction is commited otherwise it will be rolled back an an exception is throw in the TransactionScopes Dispose() method.

SubSonic itself will create an new Connection for every statement you execute (no bug, it's by desing) but not practical for Transactions. This is the reason why the SharedDbConnectionScope() exists. It works similar to the TransactionScope (if a new AutomaticConnectionScope detects that there is a current SharedDbConnectionScope() it's connection will be used. Otherwise a new connection will be created.

By the way, the using syntax is nothing else than this:

var obj = new ObjectThatImplementsIDisposable();
try
{

}
finally
{
    obj.Dispose();
}

Long story short: It does not affect your transaction if you run it in a thread or BackgroundWorker. However, you should keep in mind that, if you use a SharedDbConnecionScope() even queries from other threads will use them an I don't think the SqlClient library is thread safe (but I can be wrong, but MySqlClient definitely isn't.

Conculstion: I would switch to the TransactionScope because it is easy to use, flexible, generic (and if you decide one day to switch to mysql or oracle with your app, you don't have to worry)

Reading you first part of the question:
- I think it is a bad desing to let the BackGroundWorker's DoWork method throw an Exception. But you can use this approach:

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 ;-)");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文