我有以下代码可以完成一些数据库工作:
[WebMethod]
public void FastBulkAdd(int addmax){
Users[] uploaders = db.Users.Take(addmax).ToArray();
Parallel.ForEach(uploaders, item =>
{
Account account;
lock (this)
{
account = item.Account;
}
}
每个用户都有1个帐户,通过外键在DB中的另一个表中引用(我确定每个用户只有1个帐户)。我必须锁定那段代码,因为多线程数据库连接会产生错误。当我将此设置addmax设置为1(允许1个线程执行)时,它运行正常,但如果addmax大于1且执行了多个线程,则帐户将始终为null,这将生成稍后会有例外。这几乎就像锁被忽略了一样。
更新:我不相信帐户永远是空的,所以我做了以下事情:
int tries = 0;
while (account == null && tries < 100)
{
lock (this)
{
account = item.Account;
}
tries++;
}
它有效。不是一个非常简洁的解决方案。我想知道问题的原因,以便将来可以避免这种设计危险。
答案 0 :(得分:2)
item.Account
进行数据库查找,对吗?您可以立即用所有上传者帐户的批量选择替换它吗?这样你只需要选择一个数据库进行选择,然后一个命中数据库就可以稍后进行批量更新,而且你不关心同步数据库访问(无论如何,每次额外命中需要花费大量时间)
答案 1 :(得分:0)
而不是锁定this
创建private static object
并锁定它;你可以参考this thread。
此外,您需要验证item.Account不为null。另一个问题是,即使您锁定了Account
,您似乎也在以后的代码中使用它。这似乎不对,即使您正在锁定,然后它可能会在您将其保存到数据库的部分中更改,因为它未锁定。请参阅以下示例;
lock (this)
{
account = item.Account;
}
DoSomeDatabaseOperation(account); // the account may change here when another thread is also operating.
您也可以调试并行操作;请参阅this msdn page。
答案 2 :(得分:0)
您可以使用[MethodImpl(MethodImplOptions.Synchronized)] 例如
[MethodImpl(MethodImplOptions.Synchronized)]
[WebMethod]
public void FastBulkAdd(int addmax)
{
}
有关详细信息,请参阅以下链接。 http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions.aspx