如何在交易期间锁定数据

时间:2016-05-22 18:29:34

标签: sql-server transactions isolation-level

我开始使用SQL Server数据库,我很难理解Transaction Isolation Levels以及它们如何锁定数据。

我正在尝试完成以下简单任务:

  • 在SQL存储过程中接受一对整数[ID,counter]
  • 确定某个表中是否存在ID:SELCT COUNT(*) FROM MyTable WHERE Id = {idParam}
  • 如果前一个COUNT语句返回0,请插入此ID和计数器: INSERT INTO MyTable(Id, Counter) VALUES({idParam}, {counterParam})
  • 如果COUNT语句返回1,则更新现有记录:UPDATE MyTable SET Counter = Counter + {counterParam} WHERE Id = {idParam}

现在,我知道我必须将整个存储过程包装在一个事务中,并且根据this MS article,适当的隔离级别将是SERIALIZABLE(它说:没有其他事务可以修改具有的数据已被当前事务读取,直到当前事务完成)。如果我错了,请纠正我。

假设我使用ID = 1调用过程,因此第一个查询woluld为SELCT COUNT(*) FROM MyTable WHERE SomeId=1(第一个事务开始)。然后,在执行此查询之后,立即调用ID为2的过程(第二个事务开始)。

我无法理解的是在这种情况下执行存储过程期间会锁定多少数据:

  • 如果第一个事务的第一个查询返回0个记录,这是否意味着第一个事务没有锁定,其他事务在第一个事务尝试之前能够INSERT ID = 1?
  • 或者第一个事务是否锁定了整个表,使第二个事务等待,即使这两个事务永远不会尝试读取/更新同一行?
  • 或者第一次交易是否禁止其他人只读取/写入ID = 1的记录,直到它被选中?

1 个答案:

答案 0 :(得分:0)

如果您的过滤器位于某个索引上,那将会锁定哪些内容。因此,无论行是否已存在,它都会在事务持续期间被锁定。不过要小心 - 很容易将行锁变成更糟糕的东西,特别是全桌锁。当然,以这种方式引入死锁很容易:)

但是,我建议采用不同的方法。首先,尝试插入。如果它有效,你就完成了 - 如果它没有,你知道你可以安全地进行原子更新。非常快,非常便宜,非常可靠:)