仅在值相同时锁定?

如果我有一个在我的webservice中编辑数据库的函数,我只想让一个线程一次执行,如果他们试图编辑同一行。

void EditCheck(long checkid) { if (isCheckCosed) throw new Exception("check is already closed"); //do stuff //after i edit my check i want to close it. CloseCheck(); } 

我知道我可以锁定整个function,但随后我松开了性能,因为它几乎从来没有那个不同的线程会尝试编辑相同的检查。

有没有办法只锁定具有相同checkid的其他线程?

UPDATE

我使用OleDbConnectionMySqlConnection

 OleDbCommand oleDbCommand = AccessTrans != null ? new OleDbCommand(sql, AccessConn, AccessTrans) : new OleDbCommand(sql, AccessConn); oleDbCommand.ExecuteNonQuery(); 

MySqlCommand相同的function

然后我使用正常的INSERT和UPDATE sql命令。 并检查交易是否存在。 所以如果您想在上级function中进行交易,这个function是有效的。

从数据库中读取我将填写DataTable

 OleDbCommand oleDbCommand = AccessTrans != null ? new OleDbCommand(sql, AccessConn, AccessTrans) : new OleDbCommand(sql, AccessConn); OleDbDataAdapter dAdapter = new OleDbDataAdapter(); dAdapter.SelectCommand = oleDbCommand; dAdapter.Fill(dTable); return dTable; 

您可以使用ConcurrentDictionary将每个id映射到可以锁定的对象:

 public class Foo { private ConcurrentDictionary dictionary = new ConcurrentDictionary(); private void EditCheck(long checkid) { var key = dictionary.GetOrAdd(checkid, new object()); lock (key) { //Do stuff with key } } } 

由于您希望提高性能,因此应尽可能在最近时刻进行锁定。 使用数据库时,可以使用数据库锁定。 你有两个选择:

  1. 使用Select for update ,查看SQL选择和更新的正确方法
  2. 使用乐观锁定这是恕我直言的最佳方法, http://en.wikipedia.org/wiki/Optimistic_concurrency_control或http://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ ch05.html

请注意,这两种方法都允许您使用DB资源而不是程序化资源。 这比拟议的字典更好,为什么?

一旦你复制数据,数据库中的数据在运行时字典中被复制,你被迫同步它们,所以如果有人更新数据库并添加新的id你需要立即更新字典。

当然,这对于小型维护(例如存储库)类是可行的,但是一旦您的项目增长,您的一些同事就会忘记这些信息,您将开始发现这种类型的错误。