问题描述
如果我使用相同的ConnectionString从多个线程执行查询,是否有问题?如果两个或多个线程尝试同时发送数据会怎样?
Result
解决方法
如果正确使用,则并发连接正常
假设正确的理由,并发使用多个连接没有问题。数据库可以处理数千个并发客户端连接。
并行执行相同的慢速查询以使其更快完成,可能会使它更慢,因为每个连接都可能阻塞其他连接。许多数据库已经使查询处理并行化,产生的结果比粗略的客户端并行性要好得多。
如果您想使慢速查询更快,可以通过调查慢速原因并解决性能问题来获得更好的结果。例如,如果要插入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,send data
if(serverIsOnline)
{
using(SqlConnection connection = new SqlConnecton(globalConnectionString))
{
await connection.ExecuteAsync("INSERT .... VALUES(@serial,@test)",new {serial=serialNumber,test=testResults});
}
}
}
Dapper将生成一个参数化查询,并按名称将查询中的参数与匿名对象中的属性进行匹配。
,在这里读取连接字符串不是问题。如果要通过多个线程共享SqlConnection对象,则会遇到问题。但这不是您的代码中的情况。
,我认为这是关于ACID属性中的Isolation
的问题。请看看他们。
基于SQL标准,单个SQL查询在查询所处理的表的稳定(一致)状态下运行。因此,此定义规定,在执行过程中看不到任何更改。但是,据我所知,并不是所有的DBMS软件都完全遵循此规则。例如,某些产品和/或隔离级别允许脏读。
这里有另一个用户的详细explanation。