如何获取SQL插入和/或更新以不锁定MS SQL Server上的整个表


13

数据库工作非常新手,因此,感谢您对一个基本问题的耐心等待。我在本地计算机上运行SQL Server 2014,并且有一个小表和一个基本的客户端应用程序来测试不同的方法。我在INSERT INTOUPDATE语句中都得到了一个表锁。客户端是具有以下代码的ASP.NET应用程序:

OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();

我运行此代码,然后从Management Studio运行SELECT * FROM LAYOUTSv2。在这两种情况下,当客户端线程暂停时(即,在提交/回滚之前),SELECT查询都将挂起,直到发生提交/回滚为止。

该表已将字段LAYOUTS_key分配为主键。在属性窗口中,它表明它是唯一的并且是集群的,同时允许页面锁和行锁。该表的锁定升级设置为“禁用” ...我尝试了表和AUTO的其他可用设置,而没有进行任何更改。我已经尝试过,SELECT ... WITH (NOLOCK)并且会立即返回结果,但是正如此处和其他地方所警告的那样,这不是我应该做的。我尝试过ROWLOCKINSERTUPDATE语句上都添加提示,但是没有任何变化。

我正在寻找的行为是这样的:在提交之前INSERT,来自其他线程的查询会读取除INSERTed 之外的所有行。在UPDATE从其他线程提交查询之前,请先阅读要UPDATE编辑的行的起始版本。有什么办法可以做到吗?如果我需要提供其他信息来澄清用例,请告诉我。谢谢。


3
顺便说一句,WHERE LAYOUTS_key='" + newkey + "'出于各种原因(包括SQL注入),是完全禁止的,您应该使用参数化查询。
马丁·史密斯

1
@MartinSmith感谢您的注意...从未听说过参数化查询或SQL注入攻击。
John Riehl

@JohnRiehl,回复:注入攻击,想象一下您的用户是否设置newkey为“ something';DELETE FROM LAYOUTSv2 --”。更新将成功完成,然后清空表,因为用户通过插入撇号来操纵查询。通常,参数化查询看起来像UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?,之后,您需要?在代码中分别为(参数)分配值。
Daniel Hutmacher '16

Answers:


10

很有可能它没有锁定“整个表”。

它正在锁定表中的一行,但是您SELECT * FROM LAYOUTSv2尝试读取整个表,因此必然被该锁定阻止。

对于插入案例,您仅可以指定READPAST提示以跳过锁定的行,但是,这不会为您的UPDATE情况提供所需的结果(它将再次跳过该行,而不读取该行的起始版本)。

如果您将数据库配置为读取提交的快照隔离,则这将在两种情况下都达到预期的效果(以大量使用为代价tempdb


我将“正在读取提交的快照”更改为“ True”,现在它可以完美运行而无需任何提示。谢谢!一项后续操作...我将“允许快照隔离”设置为False ...可以吗?谢谢。
John Riehl

@JohnRiehl-是的,如果您没有明确地使用SNAPSHOT隔离,最好将其禁用,然后再启用它(如果您随后决定对您有用)。
马丁·史密斯

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.