目录
[5.定义事务的 T-SQL 语句](#5.定义事务的 T-SQL 语句)
[6.事务管理的 T-SQL 语句](#6.事务管理的 T-SQL 语句)
[①SAVE TRANSACTION语句](#①SAVE TRANSACTION语句)
[②BEGIN TRY 与 BEGIN CATCH 语句](#②BEGIN TRY 与 BEGIN CATCH 语句)
[(3)参考 T-SQL 代码示例](#(3)参考 T-SQL 代码示例)
[4.使用锁的 T-SQL 语句](#4.使用锁的 T-SQL 语句)
五、事务
1.事务的定义
事务(Transaction)是由一组 T-SQL 命令组成的集合,作为一个整体执行:要么成功执行所有语句并修改数据,要么执行失败并将数据恢复到事务开始前的状态。例如:借书登记需同时修改读者已借总数、添加借书信息,事务可避免中途中断导致的数据不一致。
2.事务的特性(ACID)
事务需遵循 4 个原则,即 ACID 特性:
- 原子性(Atomic):事务是不可分割的最小单元,要么全执行,要么全不执行。
- 一致性(Consistency):事务执行前后,数据的完整性约束(如主键、外键)保持一致。
- 隔离性(Isolation):多个事务并发执行时,彼此的操作相互隔离,互不干扰。
- 持久性(Durability):事务提交后,修改的数据会永久保存,不会因故障丢失。
3.事务并发执行的问题
数据库多线程并发执行事务时,会出现以下问题:
- 脏读:一个事务读取到另一个未提交事务的更新数据。
- 不可重复读:一个事务多次读取同一行数据,结果却不同(被其他事务修改)。
- 幻读:一个事务读取某范围数据时,其他事务对该范围执行插入 / 删除,导致前后读取的行数不一致。
4.事务的隔离性(隔离级别)
不同隔离级别可解决不同的并发问题:
- 未提交读(READ UNCOMMITTED):允许读取未提交的事务数据,效率高,但会出现脏读、不可重复读、幻读。
- 已提交读(READ COMMITTED):仅读取已提交的事务数据,可避免脏读,但仍存在不可重复读、幻读。
- 可重复读(REPEATABLE READ):事务修改数据时,禁止其他事务操作该数据,可避免脏读、不可重复读,但仍存在幻读。
- 可序列化(SERIALIZABLE):事务串行执行,可避免所有并发问题,但效率极低。

注:√表示能解决此类问题,× 表示不能解决此类问题。
5.定义事务的 T-SQL 语句
(1)显式事务定义
显式定义事务的启动和结束,以BEGIN TRANSACTION开始,COMMIT TRANSACTION结束,可通过ROLLBACK TRANSACTION回滚。
-
BEGIN TRANSACTION 语句:
BEGIN { TRAN | TRANSACTION }
[ {事务名 | @事务变量名 }
[WITH MARK [description]]
]
WITH MARK [description]:在日志中标记事务,description为标记描述;使用该选项时必须指定事务名。
-
COMMIT TRANSACTION 语句:提交事务,永久保存事务执行结果:
COMMIT { TRAN | TRANSACTION }
{事务名 | [@事务变量名 ]} -
ROLLBACK TRANSACTION 语句:回滚事务,将数据恢复到事务开始前的状态:
ROLLBACK {TRAN|TRANSACTION}
[ 事务名| @事务变量名 ]
(2)隐式事务定义
无明显事务标志,需通过SET IMPLICIT_TRANSACTION ON启动;启动后形成事务链,前一个事务完成后自动启动新事务,需用COMMIT/ROLLBACK提交 / 回滚。
SQL Server 中自动启动事务的语句:ALTER、CREATE、DELETE、DROP、FETCH、GRANT、INSERT、OPEN、REVOKE、SELECT、TRUNCATE TABLE、UPDATE。
执行SET IMPLICIT_TRANSACTIONS OFF可结束隐式事务模式。
(3)自动提交事务
SQL Server 默认模式,每条语句都是一个独立事务,执行后自动提交 / 回滚;未指定显式 / 隐式事务时,默认使用此模式。
6.事务管理的 T-SQL 语句
(1)显式事务管理
①SAVE TRANSACTION语句
SQL Server 提供SAVE TRANSACTION语句,用于在事务中创建保存点,可选择性回滚到指定保存点(无需回滚整个事务),减少时间开销。语法格式:
SAVE { TRAN|TRANSACTION }
{ 保存点名 | @保存点变量}
②BEGIN TRY 与 BEGIN CATCH 语句
这是 SQL Server 2016 中用于捕获和处理事务异常的语句,可在事务管理中处理错误。语法格式:
BEGIN TRY
SQL 语句
END TRY
BEGIN CATCH
捕获错误与处理异常的语句
END CATCH
(2)隐式事务管理
隐式事务通过SET IMPLICIT_TRANSACTIONS ON开启,开启后会自动启动事务并形成事务链 ;可通过COMMIT TRAN/ROLLBACK TRAN将事务链分割为多个事务,减少回滚开销。
可结合判断语句(通过@@ERROR判断是否出错)管理事务:
--上一个事务
IF @@ERROR!=0
ROLLBACK TRAN
ELSE
COMMIT TRAN
--下一个事务
7.实战训练
(1)课题
在学生选课管理数据库 SCC 中,利用事务进行学生选课管理,需要实现的功能为:在原有班级新增 1 名学生,选修 2 门课程,所选课程学分必须大于或等于 6 分,并录入学生成绩,得分规则为百分制,范围是 0~100 分。
(2)基于该需求的事务实现思路
要完成这个功能,可通过显式事务 结合
BEGIN TRY/BEGIN CATCH处理异常,步骤如下:
- 开启事务,定义保存点(可选);
- 向学生表(如
Student)插入新学生记录;- 查询学分≥6 的课程,选择 2 门;
- 向选课成绩表(如
Score)插入这 2 门课的成绩(确保成绩在 0~100 之间);- 若所有操作无错误则提交事务,若有错误则回滚事务。
(3)参考 T-SQL 代码示例
USE SCC GO BEGIN TRY -- 开启显式事务 BEGIN TRANSACTION; -- 步骤1:新增学生(假设Student表字段:Sno学号、Sname姓名、Class班级等) INSERT INTO Student(Sno, Sname, Class, ...) VALUES('s032190125', '张三', '计科2301', ...); -- 填写实际字段值 -- 步骤2:选择2门学分≥6的课程(假设Course表字段:Cno课程号、Credit学分) -- 先查询符合条件的课程(示例选c001、c002,实际可根据需求选择) DECLARE @Course1 CHAR(4), @Course2 CHAR(4); SELECT TOP 2 @Course1=Cno, @Course2=Cno FROM Course WHERE Credit >= 6; -- 确保选2门学分≥6的课 -- 步骤3:录入这2门课的成绩(假设Score表字段:Sno、Cno、Uscore平时分、EndScore期末分等) -- 成绩确保在0~100之间 INSERT INTO Score(Sno, Cno, Uscore, EndScore) VALUES('s032190125', @Course1, 85, 90), -- 平时分、期末分符合0~100 ('s032190125', @Course2, 78, 88); -- 所有操作成功,提交事务 COMMIT TRANSACTION; PRINT '事务执行成功:新增学生及选课成绩完成'; END TRY BEGIN CATCH -- 捕获错误,回滚事务 ROLLBACK TRANSACTION; PRINT '事务执行失败:' + ERROR_MESSAGE(); -- 输出错误信息 END CATCH GO
六、锁
1.锁的概念
锁是用于控制数据库并发操作的机制,SQL Server 通过锁防止多用户操作同一数据导致的数据不一致问题。其作用是:确保事务完整性与数据库一致性,防止用户读取其他用户正在修改的数据,避免多用户同时修改相同数据;若不使用锁,数据可能逻辑错误,查询结果会异常。
2.锁的分类
SQL Server 中常用锁的类型:
- 共享锁(读锁):添加后,其他用户无法修改加锁数据,但可读取。
- 排他锁(独占锁):添加后,其他事务无法访问、修改加锁数据。
- 更新锁:用于防止死锁,一个事务最多只能获取一个更新锁权限。
- 意向锁:位于锁层次结构的底层资源,在低级锁锁定资源前提供意向标识。
- 架构锁:表修改、存储过程重编译时添加,例如修改 / 删除视图、存储过程、表等。
- 大容量更新锁 :向表大容量复制数据时,通过
TABLOCK提示使用。 - 键范围锁:事务使用可序列化隔离级别时使用的锁。
3.定义锁的关键字及作用

4.使用锁的 T-SQL 语句
-
对某一行添加锁:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM 表名 ROWLOCK WHERE id = 666
说明:设置事务隔离级别为 "未提交读",查询时对id=666的行添加共享锁。
-
锁定数据库的一个表:
SELECT * FROM 表名 WITH (HOLDLOCK)
说明:对表添加 "保持锁",事务结束前不会释放该表的共享锁。
七、游标
1.游标的概念
游标是 SQL Server 的一种数据访问机制,允许用户访问单独的数据行,对每行数据单独处理,降低系统开销;也可利用数据生成 SQL 代码并立即执行 / 输出。
游标主要用于存储过程、触发器和 T-SQL 脚本中,类似 C 语言的指针,可在结果集中前后浏览数据,指向任意位置;对结果集逐行处理时,需声明指向该结果集的游标变量。
2.游标的作用
- 从多条数据的结果集中每次提取一条记录。
- 与 SQL 查询语句关联,由结果集和游标位置(指向特定记录的指针)组成。
- 允许对 SELECT 结果集中的每行执行相同 / 不同操作。
- 支持基于游标位置对表中行进行删除和更新。
3.游标的组成与声明
游标由游标结果集 (定义游标的 SELECT 语句返回的行集合)和游标位置(指向结果集某一行的指针)组成。
游标不是数据库对象,需通过DECLARE CURSOR语句声明(类似变量声明),声明时关联 SELECT 语句但不执行。
4.游标声明的语法格式
DECLARE 游标名 CURSOR[LOCAL|GLOBAL]
[FORWARD_ONLY|SCROLL]
[STATIC|KEYSET|DYNAMIC|FAST_FORWARD]
[READ_ONLY|SCROLL_LOCKS|OPTIMISTIC]
[TYPE_WARNING]
FOR SELECT 语句
[FOR UPDATE [OF column_name [,...n]]]
语法参数说明
- LOCAL/GLOBAL:游标作用域,LOCAL 为局部,GLOBAL 为全局。
- FORWARD_ONLY/SCROLL:游标移动方向。
- STATIC|KEYSET|DYNAMIC|FAST_FORWARD:游标类型定义。
- READ_ONLY|SCROLL_LOCKS|OPTIMISTIC:游标或基表的访问属性。
- TYPE_WARNING:游标类型隐式转换时,向客户端发送警告。
- FOR UPDATE :指定游标中可更新的列;带
OF column_name则仅能修改指定列,否则可修改所有列。