14

如果我有一个在我的网络服务中编辑数据库的函数,如果他们尝试编辑同一行,我只希望一个线程一次执行。

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;
4

2 回答 2

25

您可以使用 aConcurrentDictionary将每个 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
        }
    }
}
于 2013-09-25T15:26:52.907 回答
0

由于您想提高性能,您应该尽可能在最近的时刻锁定。当您使用数据库时,您可以使用数据库锁定。你有两个选择:

  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您需要立即更新字典。

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

于 2013-09-26T06:29:56.263 回答