C# 停止使用DB的线程
我正在编写一个自动完成脚本 当用户停止键入时,他的输入将发送到服务器,服务器将在DB中查找一些匹配项 如果要找人,“奥巴马”应该返回“巴拉克·奥巴马” 我希望此搜索限制为~500毫秒。如果需要更长时间,我想中止搜索,只返回及时找到的结果 我首先寻找一个完美的匹配(这一个不会被打断),然后我寻找一个部分匹配(这一个可以被打断):C# 停止使用DB的线程,c#,mysql,multithreading,C#,Mysql,Multithreading,我正在编写一个自动完成脚本 当用户停止键入时,他的输入将发送到服务器,服务器将在DB中查找一些匹配项 如果要找人,“奥巴马”应该返回“巴拉克·奥巴马” 我希望此搜索限制为~500毫秒。如果需要更长时间,我想中止搜索,只返回及时找到的结果 我首先寻找一个完美的匹配(这一个不会被打断),然后我寻找一个部分匹配(这一个可以被打断): 评分是一种便于对结果进行排序的结构 private struct Scoring { public string value; public int s
private struct Scoring
{
public string value;
public int score;
}
目标是快速获得结果(不一定全部) 问题
- 我在
conn.Close()上~30秒后随机获得Timeoutexception代码>行
- 我在第一个
Cmd.ExecuteReader()上随机获得NullReferenceException代码>调用
FindOtherBrands
我猜TimeoutException是因为我在命令执行期间试图关闭连接,我可以删除/取消该查询吗?我会采取不同的方法。由于您查询的是一个自然异步的数据库,因此可以使用
async wait
来查询数据。这样,您就可以传递一个设置为超时的CancellationToken
,您将在每次读取时监视该超时:
例如:
private async Task FindOtherBrands(string term,
Dictionary<int, Scoring> results,
CancellationToken cancellationToken)
{
MySqlCommand cmd;
string requete;
requete = "SELECT m.id, m.nom as label
FROM marque m
WHERE m.nom LIKE '" + term + "%'";
cmd = new MySqlCommand(requete, conn);
var Rd = await cmd.ExecuteReaderAsync();
while (Rd != null && await Rd.ReadAsync())
{
cancellationToken.ThrowIfCancellationRequested();
int id = int.Parse(Rd["id"].ToString());
if (!results.ContainsKey(id))
{
results.Add(id, new Scoring()
{
score = 100,
value = Rd["label"].ToString()
});
}
}
Rd.Close();
requete = "SELECT m.id, m.nom as label
FROM marque m
WHERE m.nom LIKE '%" + term + "%'";
cmd = new MySqlCommand(requete, conn);
Rd = await Cmd.ExecuteReaderAsync();
while (Rd != null && await Rd.ReadAsync())
{
cancellationToken.ThrowIfCancellationRequest();
int id = int.Parse(Rd["id"].ToString());
if (!results.ContainsKey(id))
{
results.Add(id, new Scoring()
{
score = 10,
value = Rd["label"].ToString()
});
}
}
Rd.Close();
}
旁注-您的查询很容易被SQL注入。不应该使用字符串连接。请改用查询参数。您使用的是哪个.NET版本?在中止线程之前关闭数据库资源是明智的。遗憾的是,数据库无法在一段时间内返回所有结果。您可以请求所有结果,但不能保证数据库在找到结果后会立即将其发送给您。唯一可靠的方法是在循环中请求第n个结果并设置命令超时。它的效率非常低。我使用.NET4.5@罗伯特麦基:我知道,这就是为什么我搜索
name=“{term}”
然后搜索name,比如“{term}%”
,最后搜索name,比如“%%{term}%”
你不需要使用单独的线程。只需设置commandTimeout属性。在try/catch块中使用,这样就可以捕获数据库命令超时,但这样很可能会得到所有结果,或者没有结果。
private struct Scoring
{
public string value;
public int score;
}
private async Task FindOtherBrands(string term,
Dictionary<int, Scoring> results,
CancellationToken cancellationToken)
{
MySqlCommand cmd;
string requete;
requete = "SELECT m.id, m.nom as label
FROM marque m
WHERE m.nom LIKE '" + term + "%'";
cmd = new MySqlCommand(requete, conn);
var Rd = await cmd.ExecuteReaderAsync();
while (Rd != null && await Rd.ReadAsync())
{
cancellationToken.ThrowIfCancellationRequested();
int id = int.Parse(Rd["id"].ToString());
if (!results.ContainsKey(id))
{
results.Add(id, new Scoring()
{
score = 100,
value = Rd["label"].ToString()
});
}
}
Rd.Close();
requete = "SELECT m.id, m.nom as label
FROM marque m
WHERE m.nom LIKE '%" + term + "%'";
cmd = new MySqlCommand(requete, conn);
Rd = await Cmd.ExecuteReaderAsync();
while (Rd != null && await Rd.ReadAsync())
{
cancellationToken.ThrowIfCancellationRequest();
int id = int.Parse(Rd["id"].ToString());
if (!results.ContainsKey(id))
{
results.Add(id, new Scoring()
{
score = 10,
value = Rd["label"].ToString()
});
}
}
Rd.Close();
}
private async Task<bool> RunWithTimeoutAsync(TimeSpan timeout)
{
bool finished;
try
{
var cancellationTokenSource = new CancellationTokenSource(timeout);
await FindOtherBrandsAsnyc(term,
results,
cancellationTokenSource.CancellationToken);
finished = true;
}
catch (OperationCanceledException e)
{
// Handle
}
return finished;
}