1、为什么SQLServer有NOLOCK关键字?
SQLServer未创建查询相当于在不同的查询分析器中创建查询会话。一个典型的例子是,如果您在未正确关闭事务的情况下使用事务插入或操作某个表,其他对数据表的会话查询将被阻塞,因此无法完成查询操作。这个时候有两个解决方案,第一个查询堵塞的对话id然后杀掉会话id,
第二种可以使用WITH(NOLOCK)忽略阻塞的关键字会话直接查询结果。
简单来说NOLOCK关键字的作用是防止查询时被其他会话堵塞,从而顺利完成查询操作。
2、SQLServer有NOLOCK有什么问题
使用NOLOCK关键字可以避免阻塞,导致无法查询数据,但使用该关键字可能会导致数据脏读。以下是一个例子
2.1 创建数据表
CREATE TABLE [dbo].[userInfo] ( [id] varchar(32) COLLATE Chinese_PRC_CI_AS NOT NULL, [userName] nvarchar(30) COLLATE Chinese_PRC_CI_AS NULL, [birthday] [dbo].[birthday] NULL, CONSTRAINT [PK__userInfo__3213E83F0505C75D] PRIMARY KEY CLUSTERED ([id]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO INSERT INTO [dbo].[userInfo] ([id], [userName], [birthday]) VALUES ('123', N'小明', '2005-01-02 12:30:00.000'); INSERT INTO [dbo].[userInfo] ([id], [userName], [birthday]) VALUES ('125', N'小孙', '2005-01-02 12:30:00.000');
2.2 创建时候 会话id 为58 开启事务 不关闭事务
begin tran insert into userInfo (id,userName,birthday) values 2015-01-02 12:30:00.000') --commit tran
2.3 当前会话(58)也可以查询数据
事务尚未提交 此时,数据仍在内存中,未保存在数据库中
select * from userInfo
2.4 新的查询会话 当前新建的id是51
select * from userInfo; select * from userInfo WITH(NOLOCK);
2.5 杀死58会话进程
declare @spid int Set @spid = 58 --锁表进程 declare @sql varchar(1000) set @sql='kill ' cast(@spid as varchar) exec(@sql)
3、NOLOCK使用场景
使用频繁操作的表(插入、更新、删除)NOLOCK很合适,但要考虑脏读。
不经常修改的数据表节省了锁定表的时间,大大加快了查询速度。
可以考虑牺牲数据安全性来提高查询效率;
允许脏读的业务逻辑不适合电商、银行等数据完整性要求严格的场景。
当使用NoLock它允许阅读已修改但尚未结束的数据。因此,应考虑transaction不建议使用事务数据的实时完整性。
4、nolock和with(nolock)的区别
三种查询写法
SELECT * FROM A NOLOCK; SELECT * FROM A (NOLOCK); SELECT * FROM A WITH(NOLOCK);
1、SQLServer2005版只支持with(nolock)关键字
2、with(nolock)很容易指定索引
3.不能使用跨数据库服务器查询语句with (nolock) 只能用nolock,查询同一数据服务器时 两者都可以使用
-- SQL Server 建议在2008版之后使用WITH(NOLOCK)写法。
5、表解锁脚本
-- 查询被锁表 select request_session_id spid ,OBJECT_NAME(resource_associated_entity_id) tableName from sys.dm_tran_locks where resource_type='OBJECT'; --参数说明 spid 锁表进程 ;tableName 被锁表名 -- 解锁语句 需要拿到spid然后杀死缩表过程 declare @spid int Set @spid = 57 --锁表进程 declare @sql varchar(1000) set @sql='kill ' cast(@spid as varchar) exec(@sql)
IT技术共享社区
个人博客网站:https://programmerblog.xyz
文章推荐程序员效率:绘制流程图中常用的工具程序员效率:常用的在线笔记软件远程办公:常用的远程协助软件,你知道吗?51单片机程序下载,ISP串口基础知识硬件:断路器、接触器、继电器基础知识