Sql Server 数据库事务与锁,同一事务更新又查询锁?期望大家来解惑
我有一个People表,有三行数据:

如果我们没详细了解数据库事务执行加锁的过程中,会不会有这样一个疑问:如下的这段 SQL 开启了事务,并且在事务中进行了更新和查询操作。
BEGIN TRAN
update People set Name='张三' where id=1;
select * from People where id=1;
commit tran
我们知道sql server数据库的默认事务级别是READ COMMITTED(已提交的读取),我们再看一下已提交读事务隔离级别描述:
允许事务读取另一个事务以前读取(未修改)的数据,而不必等待第一个事务完成。 SQL Server数据库引擎将保留 (对所选数据) 获取的写入锁,直到事务结束,但读取锁将在执行 SELECT 操作后立即释放。 这是SQL Server数据库引擎默认级别。
那么我们在READ COMMITTED 隔离级别下更新People表数据库,按照这个逻辑在id=1的数据行上添加排它锁(X锁)并等到事务提交后才会释放锁。
但是事务继续执行查询,在READ COMMITTED隔离级别下 Select 会对查询数据施加共享锁(S锁)。因为有排它锁,所以查询无法获得共享锁需要等待排它锁释放,如果按照这个逻辑的话这个事务自身就死锁无法执行了。
但这个事务还是会正常执行完成,针对这个疑问,那么我们看下数据库的事务和锁:
数据库引擎隔离级别
ISO 标准定义了以下隔离级别,SQL Server数据库引擎支持所有这些隔离级别:
| 隔离级别 | 定义 |
|---|---|
| 未提交的读取 | 隔离事务的最低级别,只能保证不读取物理上损坏的数据。 在此级别上,允许脏读,因此一个事务可能看见其他事务所做的尚未提交的更改。 |
| 已提交的读取 | 允许事务读取另一个事务以前读取(未修改)的数据,而不必等待第一个事务完成。 SQL Server数据库引擎将保留 (对所选数据) 获取的写入锁,直到事务结束,但读取锁将在执行 SELECT 操作后立即释放。 这是SQL Server数据库引擎默认级别。 |
| 可重复的读取 | SQL Server数据库引擎会保留对所选数据获取的读取和写入锁定,直到事务结束。 但是,因为不管理范围锁,可能发生虚拟读取。 |
| 可序列化 | 隔离事务的最高级别,事务之间完全隔离。 SQL Server数据库引擎保留对所选数据获取的读取和写入锁定,这些锁将在事务结束时释放。 SELECT 操作使用分范围的 WHERE 子句时获取范围锁,主要为了避免虚拟读取。 注意: 请求可序列化隔离级别时,复制的表上的 DDL 操作和事务可能失败。 这是因为复制查询使用的提示可能与可序列化隔离级别不兼容。 |

SQL Server数据库引擎使用不同的锁模式锁定资源,这些模式确定并发事务如何访问资源。
T-SQL 设置事务隔离级别,只对当前会话连接一直有效
SET TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SNAPSHOT
| SERIALIZABLE
}
锁模式
下表显示了SQL Server数据库引擎使用的资源锁模式。
| 锁模式 | 说明 |
|---|---|
| 共享 (S) | 用于不更改或不更新数据的读取操作,如 SELECT 语句。 |
| 更新 (U) | 用于可更新的资源中。 防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。 |
| 排他 (X) | 用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。 确保不会同时对同一资源进行多重更新。 |
| 意向 | 用于建立锁的层次结构。 意向锁包含三种类型:意向共享 (IS)、意向排他 (IX) 和意向排他共享 (SIX)。 |
| 架构 | 在执行依赖于表架构的操作时使用。 架构锁包含两种类型:架构修改 (Sch-M) 和架构稳定性 (Sch-S)。 |
| 大容量更新 (BU) | 在将数据大容量复制到表中且指定了 TABLOCK 提示时使用。 |
| 键范围 | 当使用可序列化事务隔离级别时保护查询读取的行的范围。 确保再次运行查询时其他事务无法插入符合可序列化事务的查询的行。 |
锁兼容性
锁兼容性控制多个事务能否同时获取同一资源上的锁。 如果资源已被另一事务锁定,则仅当请求锁的模式与现有锁的模式相兼容时,才会授予新的锁请求。 如果请求锁的模式与现有锁的模式不兼容,则请求新锁的事务将等待释放现有锁或等待锁超时间隔过期。 例如,没有与排他锁兼容的锁模式。 如果具有排他锁(X 锁),则在释放排他锁(X 锁)之前,其他事务均无法获取该资源的任何类型(共享、更新或排他)的锁。 另一种情况是,如果共享锁(S 锁)已应用到资源,则即使第一个事务尚未完成,其他事务也可以获取该项的共享锁或更新锁(U 锁)。 但是,在释放共享锁之前,其他事务无法获取排他锁。
下表显示了最常见的锁模式的兼容性。

查看执行时锁的情况
通过锁的兼容性模式我们知道在id=1的行上添加了排它锁,那么它就无法再接收任何锁,那我们调试这个事务看看锁的情况。

我们调试到第3行,这个时候看下锁的情况,此时事务添加了key(行)排它锁X锁,page(页)和object(表)添加了意向排它锁IX锁。
SELECT
resource_type,
resource_database_id,
resource_description,
request_mode,
request_type,
request_session_id,
request_owner_type,
request_owner_id,
lock_owner_address
FROM sys.dm_tran_locks where request_owner_type='transaction'

然后我们再继续调试到第4行,此时还没提交事务,排它锁X依然存在,但是没有S锁。

我们知道在读提交事务隔离级别下,S锁是使用完了就释放的,所以我们用SQL Server Profiler来监视下锁的情况,设置监控的项为lock,然后设置筛选条件。


上面我已经将 张三1 改为了 张三,我们再将 张三 改回 张三1,并启动监控。
BEGIN TRAN
update People set Name='张三1' where id=1;
select * from People where id=1;
commit tran

可以看到事务 transactionid=30010685 的锁监控 :
- 首先申请IX更新意向锁(object,page) 准备更新,然后获得行上的X排它锁进行更新,更新后释放了行锁和page锁(EventClass= Lock:released,Mode=0-null)。
- 等查询时申请page页IS意向读取锁,并获得行S锁读取数据后释放行锁和page页锁。
- 最后还有几个顺序释放,依次是key、page、Object,这里恰好和上面调试还没提交事务时查询sys.dm_tran_locks的锁情况一样,也就是说事务提交后依次又进行了一遍释放。
通过上面我们得出结论,事务里面并不是取得了X锁要等事务结束后才释放,在事务执行过程中也是有释放的,只是事务还保持着对于资源锁的逻辑标识,防止其它事务并发(这里是我推断的,没找到相关文献,望大佬指正)。
所以事务是在锁上更宏观的逻辑隔离,事务隔离级别只是在业务上保证数据符合隔离级别预期,至于事务中如何控制锁是基于数据库内在设计,而不能通过事务的描述去推断锁过程。
我查阅网上很多博文和官方资料都是讲事务和锁概念,有时候结合两种也是模棱两可看不出什么强联系,没有讲事务执行过程中锁是如何变化的,不知道我这篇推论是否正确,欢迎指正。
再次验证
我将事务隔离级别设置为REPEATABLE READ(可重复读),然后调试到commit行还没提交,我们看跟踪的锁和事务锁表dm_tran_locks查询的结果,按照REPEATABLE READ描述,select查询的S锁会在事务提交后释放,我们看看截图情况

开启了SQL Server Profiler结果,查询id=3后S锁已经释放。

再查dm_tran_locks表,表中依然显示事务获取了S锁,并且 resource_description=98ec012aa510 资源描述和上面跟踪是对应的。

最后我们执行完调试,跟踪锁显示又按照顺序释放了一遍锁

Sql Server 数据库事务与锁,同一事务更新又查询锁?期望大家来解惑的更多相关文章
- SQL Server 数据库的维护(三)__事务(transaction)和锁
--维护数据库-- --事务(transaction)和锁-- --事务(transaction)-- --概述: 事务是指封装了一组T-SQL语句的单个逻辑单元.单元中的所有语句作为一个整体,在满足 ...
- SQL Server 数据库表的统计信息的更新
最近在调整基础信息数据时,新增了几个客户类型,意想不到的事情发生了,在使用新增的客户类型作为 查询条件查询报表时,居然出现了超时的现象,但是用其他以前的客户类型查询就没有问题,用一个 ...
- SQL Server - 数据库初识
在互联网笔试中,常遇到数据库的问题,遂来简单总结,注意,以 Sql Server 数据库为例. 数据库 数据库系统,Database System,由数据库和数据库管理系统组成. 数据库,Data ...
- SQL Server 数据库项目
ylbtech-.NET Framework: SQL Server 数据库项目 SQL Server 数据库项目 类型:SQL Server 用于创建 SQL Server 数据库的项目 1. 新建 ...
- 使用 Oracle GoldenGate 在 Microsoft SQL Server 和 Oracle Database 之间复制事务
使用 Oracle GoldenGate 在 Microsoft SQL Server 和 Oracle Database 之间复制事务 作者:Nikolay Manchev 分步构建一个跨这些平台的 ...
- SQL Server 表的管理_关于事务的处理的详解(案例代码)
SQL Server 表的管理_关于事务的处理的详解(案例代码) 一.SQL 事务 1.1SQL 事务 ●事务是在数据库上按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以由某种数据库程序 ...
- SQL Server 表的管理_关于事务操作的详解(案例代码)
SQL Server 表的管理_关于事务操作的详解(案例代码) 1.概念 事务(transaction): 是将多个修改语句组合在一起的方法,这个方法中的所有语句只有全部执行才能正确完成功能.即要么全 ...
- Sql Server数据库备份和恢复:原理篇
本文与您探讨为什么Sql Server有完整备份.差异备份和事务日志备份三种备份方式,以及为什么数据库又有简单模式.完整模式和大容量日志模式这三种恢复模式.本文内容适用于2005以上所有版本的Sql ...
- 人人都是 DBA(V)SQL Server 数据库文件
SQL Server 数据库安装后会包含 4 个默认系统数据库:master, model, msdb, tempdb. SELECT [name] ,database_id ,suser_sname ...
- 《SQL Server企业级平台管理实践》读书笔记——SQL Server数据库文件分配方式
1.文件分配方式以及文件空间检查方法 最常用的检查数据文件和表大小的命令就是:sp_spaceused 此命令有三个缺陷:1.无法直观的看出每个数据文件和日志文件的使用情况.2.这个存储过程依赖SQL ...
随机推荐
- 京东薅羊毛脚本-Docker
一.安装好docker,然后创建容器: 注1:如果是旁路由,建议用--network host \代替-p 5678:5678 \这一行. 注2:如果想要看到lxk0301大佬的js脚本,并且重新部署 ...
- 第一章 excel与数据格式
part1 数据缘何而来 excel中常见的文件格式有xls与xlsx,推荐后者(空间小.容量大.速度快等特点) 单个excel文件为工作簿,其下包含工作表sheet(最多255),sheet中的每个 ...
- MYSQL 变更账号密码
#1 首先找到Mysql[安装的路径],切换到对应的bin目录,例如安装在D盘 C:User\Administrator> d:(输入盘符回车) D:\> cd D:\MySQL\MySQ ...
- imx6ull调试记录——开发环境搭建
搭建开发环境之网络环境 代码编译环境准备 换源 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo vim /etc/apt/so ...
- 给jui(dwz)的navTab换一套漂亮的图标
上次讲了给jui(dwz)的菜单树换一套漂亮的图标,这次讲一下在点击菜单后,怎么把设置的漂亮图标带到navTab上去. 官方的navTab是这样显示的,除了默认的我的主页外,tab页上只有标题没有图标 ...
- 如何在 Apinto 实现 HTTP 与gRPC 的协议转换 (下)
上文给大家详细介绍了在 Apinto 上实现 HTTP 与 gRPC 的协议转换的基本内容,本篇我们将继续讲解如何在 Apinto-Dashboard 中进行配置. 配置 Apinto Apinto ...
- 使用 GVM 搭建可维护的 Golang 开发环境
当你想完成 Golang 开发环境的便捷安装以及随时更新和保障多个版本的 Golang 共存的时候,就需要使用到 Golang 的专门版本管理工具 --gvm 本篇随笔记录了在 Ubuntu 下安装使 ...
- webgl 系列 —— 绘制猫
其他章节请看: webgl 系列 绘制猫 上文我们了解了如何绘制渐变彩色三角形,明白了图形装配.光栅化,以及片元着色器计算片元的颜色. 现在如果让你绘制如下一只猫.难道绘制很多三角形,然后指定它们的颜 ...
- uni-app云开发入门
云函数 首先创建一个uniapp项目,创建项目时选择启用uniCloud云开发. 创建项目成功后,按照下面的步骤进行开发. 创建云函数 1.关联云服务器 2.创建云函数 一个云函数可以看成是一个后 ...
- jquery二级菜单。显示了jquery的方便
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...