c# - 来自后台 worker 冲突的查询?

标签 c# multithreading backgroundworker

如果我使用相同的ConnectionString从多个线程执行查询,是否会有问题?如果两个或多个线程尝试同时发送数据会怎样?

string globalConnectionString = @"some_stringHere!";

//create new backgroundWorker if new logFile is created (txt file).
// ....
    
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
   // get some data from created logFile
   string serialNumber = getSerialNumber(logFile);
   string testResult = getTestResult(logFile);
       
   // if server is online, send data
   if(serverIsOnline)
   {
      using(SqlConnection connection = new SqlConnecton(globalConnectionString))
      {
         SqlCommand someCommand = new SqlCommand("some insert/update command here!", connection);
         connection.Open();
         Command.ExecuteNonQuery();
         connection.Close();
      }
   }
}

最佳答案

如果正确使用并发连接就可以了
假设正确的理由,并发使用多个连接没有问题。数据库可以处理数千个并发客户端连接。
并行执行相同的慢速查询以使其完成得更快,可能会使其变得更慢,因为每个连接都可能阻塞其他连接。许多数据库已经使查询处理并行化,与粗略的客户端并行性相比,产生的结果要好得多。
如果您想使慢速查询更快,则可以通过调查慢速原因并解决性能问题来获得更好的结果。例如,如果要插入1万行,则使用SqlBulkCopy或BULK INSERT加载行要比执行10K INSERT快,而INSERT最终会相互阻塞以访问同一张表甚至数据页
您可以使用相同的连接来执行异步查询(例如,使用ExecuteNonQueryAsync()ExecuteReaderAsync()等,前提是它们一个接一个地执行。)您不能在同一连接上执行多个并发查询,至少不能不经过一些麻烦而已。
真正的问题
真正的问题是首先使用BackgroundWorker。自2012年引入async/await以来,该类已过时。使用BGW,很难组合多个异步操作。可以通过Progress<T>类获得进度报告,并可以通过CancellationTokenSource进行协作取消。检查Async in 4.5: Enabling Progress and Cancellation in Async APIs以获得详细说明。
您可以仅使用await command.ExecuteNonQueryAsync()替换代码中的BGW调用。您可以创建一个异步方法来执行将数据插入数据库的操作:

private async Task InsertTestData(string serialNumber,string testResult)
{
   // if server is online, send data
   if(serverIsOnline)
   {
      using(SqlConnection connection = new SqlConnecton(globalConnectionString))
      {
         var someCommand = new SqlCommand("some insert/update command here!", connection);
         someCommand.Parameters.Add("@serial",SqlDbType.NVarChar,30).Value=serialNumber;
         ...
         connection.Open();
         Command.ExecuteNonQueryAsync();
      }
   }
}
如果检索序列号和测试数据很耗时,则可以使用Task.Run在后台运行它们:
   string serialNumber = await Task.Run(()=>getSerialNumber(logFile));
   string testResult = await Task.Run(()=>getTestResult(logFile));
   await InsertTestData(serialNumber,testResult);
您还可以使用像Dapper这样的库来简化数据库:
private async Task InsertTestData(string serialNumber,string testResult)
{
   // if server is online, send data
   if(serverIsOnline)
   {
      using(SqlConnection connection = new SqlConnecton(globalConnectionString))
      {
         await connection.ExecuteAsync("INSERT .... VALUES(@serial,@test)",
                               new {serial=serialNumber,test=testResults});
      }
   }
}
Dapper将生成一个参数化查询,并按名称将查询中的参数与匿名对象中的属性进行匹配。

关于c# - 来自后台 worker 冲突的查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64328828/

相关文章:

c# - TcpClient 自动重新连接

c# - C# 实现中的二叉搜索树

ios - 如何在特定线程上锁定 NSLock

multithreading - Kettle 6.0.1.0 中的 "Serial Single Threaded"转换引擎类型是什么?

c# - 后台工作人员完成后,我想更改表单上的标签。我应该在哪里添加这段代码?

c# - 我如何编码列表<int>?

c# - 在应用程序状态中存储通用列表

objective-c - 在 OSX 中为给定进程禁用定时器合并

c# - 后台 worker 同步

wpf BackgroundWorker - 关于更新 UI