我一直在寻找答案,但我无法找到问题的确切答案。
问题是由于我的数据库中的事务锁定,我实际上遇到了一些SQL问题。我想知道,默认情况下,SELECT语句会锁定一个表吗?我发现如果我使用诸如HOLDLOCK或TABLOCK之类的表提示,select会锁定表,直到它完成,但是当没有指定表提示时,SQL的行为是什么?联接会影响它的行为吗?
另一个问题,请看下面的情景: 我在我的.NET应用程序中启动连接和事务,并将它们绑定到一个命令,该命令运行仅包含SELECT语句的存储过程。选择是否会因为交易而锁定表格?
感谢您的关注。
最好的问候。
答案 0 :(得分:2)
我想知道,默认情况下,SELECT语句会锁定一个表吗?
是。 所有事务都会创建锁。 并非所有锁都阻塞(共享锁通常不是),但所有与数据库交互的事务都会创建锁。锁定是查询引擎如何跟踪它正在编写或正在阅读的内容。
即使您指定NOLOCK或READUNCOMMITTED(您通常不想这样做)you'll still get locks,因为数据需要保持一致,即使它是脏的,并且锁确保它是。也就是说,即使它返回未提交的记录(脏),也没有不完整或部分更改的记录(不一致)。
我发现如果我使用诸如HOLDLOCK或TABLOCK之类的表提示,select会锁定表[直到]它完成,但是当没有指定表提示时,SQL的行为是什么?
没有默认的锁定提示。查询引擎动态确定它需要什么。 SELECT将倾向于Shared或RangeS键范围,具体取决于查询。 INSERT / UPDATE / DELETE将倾向于独占锁。系统通常会支持最低粒度的行锁,但如果它认为应该将它们升级为页锁或表锁。注意:它们被称为“锁定提示”而不是“锁定命令”,因为如果必须,它们将忽略它们。
你会发现最接近默认锁定提示的是transaction isolation level,它通常控制事务函数中的查询方式,默认为READ COMMITTED。
动态锁定,锁定粒度,锁定升级和锁定层次结构都在the MS doc I already linked in the comment中进行了解释。
锁定系统存在巨大的细微差别和复杂性。对不同系统的相同查询可能会得到不同的锁,因为表大小不同或内存压力不同。
您还可以使用ALLOW_SNAPSHOT_ISOLATION和READ_COMMITTED_SNAPSHOT数据库选项显着修改锁定系统,但我不会轻易做出这些更改。但它确实使数据库的运行方式更像Oracle。
联接会影响它的行为吗?
非常如此。要进行连接,查询引擎通常必须扫描索引或实际表。索引就像表一样受到锁定,因此我希望Shared或RangeS-S锁出现在数据库中的对象上。
另一个问题,请看下面的场景:我在我的.NET应用程序中启动一个连接和事务,并将它们绑定到一个命令,该命令运行一个只包含SELECT语句的存储过程。选择是否会因为交易而锁定表格?
是
如果您正在使用System.Data.SqlClient.SqlTransaction,the default isolation level is ReadCommitted,那么(毫无疑问)会映射到READ COMMITTED隔离级别。但是,如果您正在使用System.Transactions,那么you will default to Serializable将映射到SERIALIZEABLE(最严格的隔离级别)。