sql-server - 如何让 SQL Server 事务使用记录级锁?

标签 sql-server transactions nonblocking record-locking table-locking

我们有一个应用程序,最初是作为桌面应用程序编写的,这是很多年前的事了。每当您打开编辑屏幕时,它都会启动一个事务,如果您单击“确定”则提交,或者如果您单击“取消”则回滚。这对于桌面应用程序来说工作正常,但现在我们正在尝试迁移到 ADO.NET 和 SQL Server,并且长时间运行的事务存在问题。

我发现当多个用户都试图同时编辑同一个表(的不同子集)时,我们会遇到问题。在我们的旧数据库中,每个用户的事务都会获得记录级锁,以锁定他们在事务期间修改的每条记录;由于不同的用户正在编辑不同的记录,每个人都有自己的锁,一切正常。但是在 SQL Server 中,只要一个用户在事务中编辑一条记录,SQL Server 就会锁定整个表。当第二个用户试图编辑同一个表中的不同记录时,第二个用户的应用程序只是锁定,因为 SqlConnection 会阻塞,直到第一个用户提交或回滚。

我知道长时间运行的事务是不好的,而且我知道最好的解决方案是更改这些屏幕,以便它们不再长时间保持事务打开。但由于这意味着一些侵入性和风险性的更改,我还想研究是否有一种方法可以按原样启动和运行此代码,这样我就知道我的选择是什么。

如何在 SQL Server 中获取两个不同用户的事务来锁定单个记录而不是整个表?

这是一个说明问题的快捷控制台应用程序。我创建了一个名为“test1”的数据库,其中有一个名为“Values”的表,其中只有 ID (int) 和 Value (nvarchar) 列。如果您运行该应用程序,它会要求修改 ID、启动事务、修改该记录,然后让事务保持打开状态,直到您按 ENTER。我希望能够

  1. 启动程序并告诉它更新ID 1;
  2. 让它获取交易并修改记录;
  3. 启动程序的第二个副本并告诉它更新 ID 2;
  4. 让它能够在第一个应用程序的交易仍处于打开状态时更新(和提交)。

目前它在第 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();
    }
}

以下是一些我已经尝试过但行为没有改变的事情:

  • 将事务隔离级别更改为“读取未提交”
  • 在 UPDATE 语句中指定“WITH (ROWLOCK)”

最佳答案

只是检查一下,但是您在 ID 列上有主键或唯一索引吗?

关于sql-server - 如何让 SQL Server 事务使用记录级锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2646439/

相关文章:

PostgreSQL for 更新语句

php - MYSQL TRANSACTION 的替代品?

java - 玩框架,promises,非阻塞线程编程

大于参数的可空数字的sql查询

c# - 将 C# MVC 应用程序连接到远程 SQL Server 数据库

sql-server - 无法更新 ssms 2016 中数据库的 COMPATIBILITY_LEVEL

java - 接收来自客户端的消息

sql - 如何在sql server中将数字转换为前缀为0的字符串

postgresql - 为什么 postgres set_config 的 is_local = true 不保留整个事务的变量?

clojure - 我可以使用 http-kit 和 core.async 制作一个完全非阻塞的后端应用程序吗?