仅在值相同时锁定?

时间:2013-09-25 15:21:38

标签: c# multithreading

如果我有一个在我的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();
    }

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

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

更新

我使用OleDbConnectionMySqlConnection

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

MySqlCommand

的相同功能

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

从数据库中读取我将填写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;

2 个答案:

答案 0 :(得分:15)

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

public class Foo
{
    private ConcurrentDictionary<long, object> dictionary = 
        new ConcurrentDictionary<long, object>();

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

答案 1 :(得分:0)

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

  1. 使用Select for update,查看Proper way to SQL select and update
  2. 使用乐观锁定,这是恕我直言的最佳方法,http://en.wikipedia.org/wiki/Optimistic_concurrency_controlhttp://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ch05.html
  3. 请注意,这两种方法都允许您使用DB资源而不是程序化资源。这比拟议的字典更好,为什么?

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

    当然,它对于小型维护(例如存储库)类是可行的,但是一旦你的项目变得越来越大,你的一些同事可能会忘记这些信息,你将开始发现这种类型的错误。