.net的sqlserver事务里,delete语句如何只锁行,不锁表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.net的sqlserver事务里,delete语句如何只锁行,不锁表相关的知识,希望对你有一定的参考价值。

我有一个多线程同步数据,需要在线程里先删老数据,再添加新数据。在线程的事务里,我先要delete table where id = ?。但是第一个线程执行完这条语句后,第二个线程无法执行这条语句,应该是该表被锁了。怎么让delete在事务里只锁行数据,不锁表。

你理解错了!

默认sqlserver都是行数据锁定,隔离级别是 read commited 也就是读取可 提交数据。

我给你举个例子!

SELECT TOP 1000
[ID]
,[DeleteBy]
,[DelDate]
FROM [dbo].[DeleteLog]
显示结果
-----------------------------------------------
ID DeleteBy DelDate
1 admin 2008-04-13 00:00:00.000
2 admin 2008-05-04 00:00:00.000
-------------------------------------------------
表数据就两行
然后我做如下操作:
打开 SQL Server Management Studio
输入:
begin transaction
DELETE FROM [HMS].[dbo].[DeleteLog]
where ID='1'

在另一个窗口中:
SELECT
[ID]
,[DeleteBy]
,[DelDate]
FROM [dbo].[DeleteLog]
where ID=1

你发现 这一个窗口被阻塞了,

但是查询

SELECT
[ID]
,[DeleteBy]
,[DelDate]
FROM [dbo].[DeleteLog]
where ID=2

可以正确返回结果。 这充分证明了,sqlserver默认隔离级别是行数据锁定。

然后你此时在第一个删除窗口 中输入

rollback

,记住前面的删除不执行,只执行rollback。

此时看一下查询
SELECT
[ID]
,[DeleteBy]
,[DelDate]
FROM [dbo].[DeleteLog]
where ID=1

那个窗口的结果已经出来了,阻塞被解除了。

========================================
当然了!你执行了全表检索肯定也是被阻塞的,因为删除操作还没提交啊,检索数据中又包含了你要删除的数据,当然被阻塞了。

你的问题出现在哪里了,你应该明白了吧!

解决这个问题其实很简单,不要长事务占用。检索的时候避开要删除的数据。

当然也可以改变隔离级别,sqlserver分为两类隔离级别,改成非阻塞类就可以。

但是我个人不推荐这么做。改变隔离级别可以如下方式:

set transaction isolation level read uncommitted
begin transaction
DELETE FROM [HMS].[dbo].[DeleteLog]
where ID='1'

这个删除没有提交

检索的时候

set transaction isolation level read uncommitted
SELECT
[ID]
,[DeleteBy]
,[DelDate]
FROM [dbo].[DeleteLog]
where ID=1

根本不会阻塞。 比较顺利,删除更新也一样。

这种方式 适合 数据量庞大的社交,天文数据库,企业管理不适合。
可以从侧面看出,你的程序并不优良,明白了否?
参考技术A 默认是key锁,也就是rowlock,一行就是一个锁,,1000行就是1000个锁,当锁数量超过5000,数据库会自动把行锁升级为表锁,这样锁就变少了,占用资源就少了。
但是,全表锁定我啥也干不了啊?所以要指定paglock,例如
update t with(paglock) where Id < 2000
一页包含大概几十页上百行,这样锁的数量也比较少,不会锁全表,但如果数据特别大,例如50W行,页锁也会有5000个,同样会升级为表锁。
但50W数据够你用的了。

SQL Server:如果从 .net 代码中取消,则存储过程中打开的事务的默认操作

【中文标题】SQL Server:如果从 .net 代码中取消,则存储过程中打开的事务的默认操作【英文标题】:SQL Server: Default action for opened transaction in a stored procedure if cancelled from .net code 【发布时间】:2018-06-01 15:18:34 【问题描述】:

我正在我的 .net 代码上执行一个存储过程。存储过程已经开始事务,只有在没有错误时才提交,否则将回滚事务。如果我要从我的 .net 代码中取消存储过程的执行,事务是提交还是回滚?

【问题讨论】:

你要取消执行是什么意思? 如果存储过程在 .NET 取消命令时尚未提交事务,则事务将回滚。如果它已经提交,取消将保留已经提交的事务,除非您从 .NET 中启动了一个事务——在这种情况下,存储过程的事务是一个嵌套事务,不会t 成功提交,直到外部事务提交。 这有助于@JeroenMostert。非常感谢。 【参考方案1】:

默认行为是在 proc 代码中以BEGIN TRAN 开始的事务将在客户端取消 proc 后保持打开状态。您可以(并且应该)将SET XACT_ABORT ON 添加到存储过程中,以便SQL Server 在应用程序取消请求或超时后自动回滚事务。这是一种最佳实践,当人们在存储过程中使用显式事务以避免无意中使事务打开的时间超过必要的时间,或者更糟糕的是,在不知情的情况下执行与打开的事务相关的其他工作时,这是一种最佳做法。

不要尝试同时在客户端和服务器上管理事务。任选其一。

【讨论】:

以上是关于.net的sqlserver事务里,delete语句如何只锁行,不锁表的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver跳过锁表等待

sqlserver 2005 事务

sqlserver 2005 事务

SqlServer事务语法及使用方法

SqlServer事务语法及使用方法

sql 事务自动回滚