为什么“插入查询”之前的“开始事务”会锁定整个表?

为什么“插入查询”之前的“开始事务”会锁定整个表?

我编写了一个存储过程来插入一条记录。我在“插入查询”上方添加了“开始事务”并执行查询。我注意到,另一个显示包含来自同一张表的记录的网页的应用程序在插入完成时挂起了。

为什么 Begin Transaction 会锁定整个表?写入者不应该阻碍读取者。默认情况下它应该是开启的。

我正在使用 SQL-Server 2005 Express。我也想知道 Oracle 和 MySQL 如何处理同样的情况。

答案1

Begin Transaction 是事务的开始 - 在结束事务之前,不能将任何其他数据写入表中,这是设计使然,以便在数据库上强制执行 ACID 标准。http://en.wikipedia.org/wiki/ACID

如果您需要将多个查询当作一个原子操作来执行,则可以使用事务。如果您不需要原子性,请不要使用事务!

不过,这是非常非常基础的东西——在尝试编写数据库代码之前,您可能需要重新掌握基本的数据库理论,如果您不熟悉事务等核心原则,可能会对应用程序造成严重损害。

答案2

虽然其他人所说的基本上是正确的,但这种行为取决于您使用的事务隔离级别;它从技术上来说,事务可以不锁定整个表。

如果您希望其他用户能够在您修改数据时读取您的数据,您可以将 TIL 设置为READ UNCOMMITED

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITED

当然,你需要非常小心使用此设置,因为它可能会导致任何类型的数据不一致,具体取决于其他用户当时正在做的事情。

更多信息请点击这里:

http://msdn.microsoft.com/en-us/library/ms189122.aspx
http://msdn.microsoft.com/en-us/library/ms173763.aspx

答案3

嗯,我不是 SQL Server 专家,所以我不会谈论这个。

但是,由于问题标记为“oracle”,并且发帖人还询问它在 Oracle 中是如何工作的,所以我将解决该部分。

在 Oracle 中,默认事务隔离级别为 READ COMMITTED。此外,Oracle总是在行级别进行锁定,并且永远不会将锁定升级到块(在 SQL Server 中称为页面?)级别。

因此,如果您锁定表中的行“a”,然后另一个会话尝试锁定同一张表中的行“b”,则该锁定将会成功,甚至如果行位于同一个块中。

至于“开始事务”,在 Oracle 中,如果尚未开始事务,则任何 DML 都将隐式开始事务。该事务将保持打开状态,直到会话明确提交或回滚,或被终止(在这种情况下,Oracle 将回滚该事务)。

但是,Oracle 确实有一个“开始事务”语法,即“设置事务”。这可用于开始只读或读写事务,或设置隔离级别。

只读事务的一个有趣用途是(除了只读之外),它为该事务中执行的所有查询提供与事务开始时间点一致的读取一致性。因此,一旦您执行“设置事务只读”,您执行的任何查询都将返回与事务开始时间一致的结果。(通常,查询结果与查询执行开始的时间点保持一致,但对于只读事务,事务中执行的所有查询都将与事务开始时间一致。)

答案4

写入者不应该阻碍读取者

这仅适用于快照隔离,所有其他隔离级别都要求读取器阻止写入阻止者,并且写入器阻止读取器(不考虑脏读,因为它们是不一致并且永远不应该使用)。如果您需要此行为,请使用行版本控制(链接包含解决方案)。

为什么批量插入会锁住整个表?

这实际上可能是真的,也可能不是真的。行为由你控制:

塔布洛克

指定在批量导入操作期间获取表级锁。如果表没有索引并且指定了 TABLOCK,则可以由多个客户端同时加载该表。默认情况下,锁定行为由表选项决定table lock on bulk load

欲了解更多详细信息,请阅读产品规格:控制批量导入的锁定行为

相关内容