c# - 来自后台工作者冲突的查询?
问题描述
如果我使用相同的 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();
}
}
}
解决方案
如果使用正确,并发连接是可以的
假设出于正确的原因,同时使用多个连接没有问题。数据库可以处理数千个并发客户端连接。
并行执行相同的慢查询以使其更快完成可能会使其更慢,因为每个连接都可能阻塞其他连接。许多数据库已经对查询处理进行了并行化,产生的结果比粗略的客户端并行性要好得多。
如果你想让一个慢查询更快,你可以通过调查它为什么慢并修复性能问题来获得更好的结果。例如,如果您想插入 10K 行,使用 SqlBulkCopy 或BULK INSERT
加载行比执行 10K INSERT 更快,这最终会相互阻塞以访问同一个表甚至数据页
您可以使用同一个连接来执行异步查询(例如 withExecuteNonQueryAsync()
等ExecuteReaderAsync()
,前提是它们一个接一个地执行。您不能在同一个连接上执行多个并发查询,至少在不经过一些循环的情况下是这样。
真正的问题
真正的问题是首先使用 BackgroundWorker。自 2012 年async/await
引入该类以来,该类已过时。使用 BGW 组合多个异步操作非常困难。进度报告可通过Progress<T>
课程获得,合作取消可通过CancellationTokenSource
。查看4.5 中的异步:在异步 API 中启用进度和取消以获取详细说明。
您可以仅将代码中的 BGW 调用替换为await command.ExecuteNonQueryAsync()
. 您可以创建一个异步方法来执行将数据插入数据库:
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 将生成一个参数化查询,并将查询中的参数与匿名对象中的属性按名称进行匹配。
推荐阅读
- sql - Like * 不捕获 Is Null 值
- bash - 得到 GATK 参数错误并且不明白?
- bigdata - 使用直观、现代的 UI 搜索文本挖掘/提取软件
- reactjs - 如何重新初始化 init(); 在 React 中允许 Adobe Animate SVG 文件在路线更改时重新运行?
- sql - jpa 查询中不支持 DateAdd 函数
- python-3.x - 制作自定义模糊隶属函数Python
- sas-jmp - JSL 中的学生化残差
- elasticsearch - 使用 filebeat 和通过 rsync 传输的日志
- bash - 为什么有些人在 shell 脚本中的 if 条件后加分号?
- java - 无法使用 Java 打开新窗口(基于 FXML)