【问题标题】:C# Connect to database in separate threadC# 在单独的线程中连接到数据库
【发布时间】:2012-04-18 16:19:19
【问题描述】:

我有一个位于任务栏中的应用程序并定期检查数据库(通过 SQLConnection)。如果数据库无法访问,它只会在通知图标上显示红色状态,而不是其他任何内容。这是因为用户将使用笔记本电脑在设施之间旅行,并且数据库只能在内部网络上或通过 VPN 连接时访问。

我遇到的问题是,当数据库无法访问时,我仍然希望通知图标上下文菜单能够响应。目前,如果用户在数据库尝试连接时尝试与菜单交互,则线程会因连接尝试而被锁定。

我希望数据库连接发生在一个单独的线程中,但我知道在线程之间共享连接对象是一件坏事。连接数据库后,我需要从原始线程中查询它。有什么好办法吗?

我知道我可以在一个新线程中创建一个函数并简单地检查连接是否失败,然后如果返回成功,则原始线程可以继续前进并连接它自己的数据库对象。但这种方法似乎是一个糟糕的解决方法。想法?

谢谢!


感谢您的建议 - 我从他们那里学到了很多东西。最后,我做了我从一开始就应该做的事情。每当需要定期更新数据库时,主 (UI) 线程就会启动一个新线程(包括数据库对象创建和连接)。

因此,就像 HenkHolterman 在对我的原始消息的评论中建议的那样,我真的不需要创建数据库并在单独的线程中使用它运行操作。

一旦我升级到 VS2010,我肯定会对使用 SqlConnection.OpenAsync 感兴趣。

再次感谢。

【问题讨论】:

  • 为什么要在原帖中查询?它可能会再次阻塞。

标签: c# sql-server database multithreading


【解决方案1】:

SqlConnection 没有线程关联性要求,因此您可以在单独的线程上创建和打开它,并将引用传递回 UI 线程。只要您不从多个线程同时调用同一实例上的任何属性或方法,就不会有任何问题。

使用Task 类(System.Threading.Task) 在后台启动此操作,然后调用ContinueWith 将实例的所有权转移回UI 线程。

public class TrayIconForm : Form
{
  private SqlConnection connection = null;

  private void Form_Load(object sender, EventArgs args)
  {
    TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

    Task.Factory.StartNew(() =>
      {
        var sql = new SqlConnection();
        sql.ConnectionString = "your connection string";
        sql.Open();
        return sql;
      }).ContinueWith((task =>
      {
        connection = task.Result;
        // You can access other UI elements here as needed.
      }), ui);
  }
}

有了新的asyncawait 关键字将在C# 5.0 中引入并且现在可以通过Async CTP 使用,您可以做到这一点。

private async void Form_Load(object sender, EventArgs args)
{
  connection = await Task.Run(() =>   // TaskEx.Run in the CTP
    {
      var sql = new SqlConnection();
      sql.ConnectionString = "your connection string";
      sql.Open();
      return sql;
    });
}

【讨论】:

    【解决方案2】:

    我建议使用新的C# Async CTP.,这将允许您留在 UI 线程上,从而降低复杂性。

    SqlConnection.OpenAsync

    【讨论】:

    • 有点冒险?当 .Open() 阻塞很多秒时,这并不是一个真正的选择。
    • 看起来是一个不错的解决方案,但我还没有决定通过繁重的公司流程订购 VS2010 升级 - 仍然在 VS2008 上。感谢您的建议!
    • @HenkHolterman 我想你已经尝试过了。我在 F# 中使用这种编程模型有过非常好的经验,并且强烈推荐在 C# 中使用它。
    • @HenkHolterman 异步编程的精神是要求执行长时间运行的操作,并提供回调,例如 Brian Gideon 代码中的 ContinueWith。不同之处在于将与您的应用程序相关的所有内容都保留在同一个线程上,从而减少由于线程/同步而破坏事物的风险。这甚至在 .NET 1.1 中也可用,这有多冒险?我错过了什么?
    【解决方案3】:

    使用BackgroundWorker 对象应该可以以一种简单的方式解决您的问题,但更准确地说,您希望使用线程来尝试打开连接,让 UI 线程准备好接收用户输入。

    【讨论】:

    • 后台线程打开连接后,如何从 UI 线程与其交互?是否需要在 UI 线程中创建连接对象,将其传递给连接线程,并在连接线程完成后继续?
    • 这完全取决于您需要对该连接做什么。非常小心线程安全。如果您使用在两个线程之间共享范围内的对象,请注意在使用时锁定该对象。
    • 您可以简单地将打开的连接传递给 Completed 事件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多