C#,SQLServer语言 - 块表行读取,如果需要编辑并释放锁定



我需要在对同一行执行更新逻辑时阻止行级别的数据库读取。漂亮干净的解决方案会是什么样子?这是我正在处理的一些代码:

using (SqlConnection conn = new SqlConnection(Configuration.ConnectionString)) {
conn.Open();
using (SqlTransaction tran = conn.BeginTransaction(IsolationLevel.Serializable)) {
//TODO lock table row with ID=primaryKey (block other reads and updates)
using (SqlCommand cmd = new SqlCommand("SELECT Data FROM MyTable WHERE ID=@primaryKey", conn)) { 
cmd.Parameters.AddWithValue("@primaryKey", primaryKey);
using (var reader = cmd.ExecuteReader()) {
data = PopulateData(reader);
};
}
if (isUpdateNeeded(data)) {
ChangeExternalSystemStateAndUpdateData(data) //EDIT - concurrent calls not allowed
WriteUpdatesToDatabase(conn, tran, data);    //EDIT
tran.Commit();
}

} //realease lock and allow other processes to read row with ID=primaryKey
}

编辑:

我有以下限制:

  • 代码可以同时在不同的应用程序池中执行。所以内存锁定不是一种选择
  • ChangeExternalSystemStateAndUpdateData(( 只能在 MyTable 行的范围内执行一次。并发呼叫将导致问题

通常,这里的问题不是行锁定,而是: 其他 SPID 在您的读取和更新之间获取锁定 - 这可能导致死锁情况; 此处的常见解决方法是在初始读取中获取锁定:

SELECT Data FROM MyTable WITH (UPDLOCK) WHERE ID=@primaryKey

请注意,如果另一个 SPID 显式使用NOLOCK那么他们仍然会闪电般地通过它。

您也可以尝试添加ROWLOCK,即WITH (UPDLOCK, ROWLOCK)- 就我个人而言,最初我会保持简单。由于您处于可序列化的上下文中,因此尝试过于精细可能是一个失败的原因 - 键范围锁等。

最新更新