[英]How can I get SQL Server transactions to use record-level locks?
我們的應用程序最初是作為桌面應用程序編寫的,多年前就是這樣。 無論何時打開編輯屏幕,它都會啟動一個事務,如果單擊“確定”,則會提交,或者如果單擊“取消”,則會回滾。 這適用於桌面應用程序,但現在我們正在嘗試遷移到ADO.NET和SQL Server,並且長時間運行的事務是有問題的。
我發現當多個用戶同時嘗試編輯同一個表(不同的子集)時,我們會遇到問題。 在我們的舊數據庫中,每個用戶的事務將獲取他們在事務期間修改的每個記錄的記錄級鎖定; 由於不同的用戶正在編輯不同的記錄,每個人都有自己的鎖,一切正常。 但是在SQL Server中,只要有一個用戶在事務中編輯記錄,SQL Server就會在整個表上獲得鎖定。 當第二個用戶嘗試編輯同一個表中的不同記錄時,第二個用戶的應用程序只會鎖定,因為SqlConnection會阻塞,直到第一個用戶提交或回滾。
我知道長時間運行的事務很糟糕,我知道最好的解決方案是更改這些屏幕,以便它們不再能夠長時間保持事務處理。 但是,由於這將意味着一些侵入性和風險的變化,我還想研究是否有一種方法來使這些代碼按原樣運行,因此我知道我的選擇是什么。
如何在SQL Server中獲取兩個不同用戶的事務來鎖定單個記錄而不是整個表?
這是一個快速而骯臟的控制台應用程序,用於說明問題。 我創建了一個名為“test1”的數據庫,其中一個名為“Values”的表只有ID(int)和Value(nvarchar)列。 如果您運行該應用程序,它會要求修改ID,啟動事務,修改該記錄,然后保持事務處於打開狀態,直到您按Enter鍵。 我希望能夠
目前它在第4步凍結,直到我回到應用程序的第一個副本並關閉它或按ENTER鍵以便提交。 對command.ExecuteNonQuery的調用將阻塞,直到第一個連接關閉。
public static void Main()
{
Console.Write("ID to update: ");
var id = int.Parse(Console.ReadLine());
Console.WriteLine("Starting transaction");
using (var scope = new TransactionScope())
using (var connection = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=test1;Integrated Security=True"))
{
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "UPDATE [Values] SET Value = 'Value' WHERE ID = " + id;
Console.WriteLine("Updating record");
command.ExecuteNonQuery();
Console.Write("Press ENTER to end transaction: ");
Console.ReadLine();
scope.Complete();
}
}
以下是我已經嘗試過的一些事情,沒有改變行為:
只是檢查,但ID列上是否有主鍵或唯一索引?
可能是在行鎖設置為“關閉”的情況下創建索引。
在這種情況下,查詢中的“WITH(ROWLOCK)”將不起作用。
您可以使用ALTER INDEX重新打開它們,例如:
ALTER INDEX [PK_Values] ON [Values] SET (ALLOW_ROW_LOCKS = ON)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.