本文主要讲述sqlserver事务,重点关注事务ACID特性,隔离性是重中之重,事务带来的问题(脏读、不可重复读、幻读)以及事务隔离级别需要重点关注。
事务是一组逻辑操作单元,这些操作要么全部成功,要么全部失败。SQL Server 中的事务可以包含多条 INSERT、UPDATE、DELETE 或其他语句,通常用于保证复杂操作的完整性。事务的目标是确保数据库在操作完成后保持一致性状态。
用 begin transaction 明确指定事务的开始,由 commit transaction 提交事务、rollback transaction 回滚事务到事务结束
通过设置 set implicit_transactions on 语句,将隐式事务模式设置为打开。当以隐式事务模式操作时,不必使用 begin transaction 开启事务,当一个事务结束后,这个模式会自动启用下一个事务。只需使用 commit transaction 提交事务或 rollback transaction 回滚事务即可。
Sql Server的默认模式,它将每条单独的T-SQL语句视为一个事务。如果成功执行,则自动提交,否则回滚。
SQL Server 事务遵循四个 ACID 属性,以确保数据的一致性和可靠性:
在 SQL Server 中,事务控制语句包括 BEGIN TRANSACTION、COMMIT TRANSACTION 和
ROLLBACK TRANSACTION。
以下为模拟一个事务下新增员工->更新员工工资两步操作的sql示例
BEGIN TRANSACTION;
BEGIN TRY
-- 插入新员工
INSERT INTO Employees (EmployeeID, EmployeeName, Department, Salary)
VALUES (6, 'Frank', 'Finance', 6000);
-- 更新员工工资
UPDATE Employees
SET Salary = Salary * 1.1
WHERE Department = 'IT';
-- 提交事务
COMMIT TRANSACTION;
PRINT 'Transaction committed successfully.';
END TRY
BEGIN CATCH
-- 回滚事务
ROLLBACK TRANSACTION;
PRINT 'Transaction rolled back due to an error.';
END CATCH;
在此示例中:
★★★(重点)即事务的四大特性ACID中I隔离性
脏读(Dirty Read)是指在数据库事务中,一个事务读取了另一个未提交事务中的数据。当一个事务修改数据但还没有提交时,另一个事务读取了这个未提交的数据。如果未提交的事务最终被回滚,那么另一个事务读取到的数据实际上是无效的或错误的。脏读可能导致不一致的数据状态和不正确的结果。
不可重复读(Non-repeatable Read)是指在数据库事务中,在对数据进行读取的过程中,有其他事务对数据进行了修改(UPDATE、DELETE),导致第二次读取的结果与第一次不一致。
幻读(Phantom Read)是指在数据库事务中,一个事务在相同的查询条件下多次执行范围查询时,另一个事务在该范围内进行新增操作(INSERT),导致前后范围查询的结果数目不一致。
事务隔离级别控制事务之间的相互影响,SQL Server 提供了四种主要的隔离级别:
此外,还存在两种隔离级别:
SNAPSHOT 和 READ COMMITTED SNAPSHOT 是两种基于行版本控制(Row Versioning)的隔离级别,旨在提升并发性能并减少锁争用。了解
设置事务的隔离级别
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
-- 查询操作
COMMIT TRANSACTION;
隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能 | 锁定范围 | 锁机制/行版本控制 |
---|---|---|---|---|---|---|
READ UNCOMMITTED | 允许 | 允许 | 允许 | 最快 | 无锁或最小锁 | 无锁(允许脏读) |
READ COMMITTED | 防止 | 允许 | 允许 | 常用,性能高 | 读取时短期共享锁 | 共享锁(语句级释放) |
REPEATABLE READ | 防止 | 防止 | 允许 | 较慢 | 读取时共享锁,直到事务结束 | 共享锁(事务级保持) |
SERIALIZABLE | 防止 | 防止 | 防止 | 最慢 | 锁定读取范围,直到事务结束 | 范围锁 |
SNAPSHOT | 防止 | 防止 | 防止 | 中等 | 无锁 | 行版本控制(无锁) |
READ COMMITTED SNAPSHOT | 防止 | 防止 | 允许 | 高 | 读取时短期共享锁 | 行版本控制(替代锁) |
READ UNCOMMITTED 是最低的隔离级别,允许读取未提交的数据(即脏读),不会为读取的数据加锁。
特点:
示例:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRANSACTION;
SELECT * FROM Employees WHERE Department = 'IT';
COMMIT TRANSACTION;
READ COMMITTED 是 SQL Server 的默认隔离级别。在此级别下,事务只能读取已提交的数据,防止脏读,但仍可能出现不可重复读和幻读。
特点:
示例:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;
SELECT * FROM Employees WHERE Department = 'IT';
COMMIT TRANSACTION;
在此隔离级别下,一个事务可以读取其他事务提交的最新数据,因此两次读取同一行时,数据可能会有所不同(不可重复读)。
REPEATABLE READ 隔离级别确保在同一事务中多次读取相同数据时,数据不会发生变化,防止脏读和不可重复读,但仍可能出现幻读。
特点:
示例:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
SELECT * FROM Employees WHERE Department = 'IT';
COMMIT TRANSACTION;
在此隔离级别下,事务读取的数据将被锁定,直到事务完成,确保在事务内数据一致。但新行的插入可能会导致幻读。
SERIALIZABLE 是最高的隔离级别,确保事务之间完全隔离,防止脏读、不可重复读和幻读。其实现方式是锁定读取的数据范围,防止其他事务插入或修改。
特点:
示例:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
SELECT * FROM Employees WHERE Department = 'IT';
COMMIT TRANSACTION;
选择合适的隔离级别需要在数据一致性和系统性能之间做权衡:
SQL Server 的默认隔离级别为 READ COMMITTED,但实际行为可能受行版本控制参数影响。
查询方法:
DBCC USEROPTIONS;
输出示例:
isolation level: read committed
说明:
该命令显示当前会话的默认隔离级别,但若数据库启用了行版本控制(如 READ_COMMITTED_SNAPSHOT),实际隔离行为可能为 READ COMMITTED SNAPSHOT。
通过查询系统视图 sys.databases,可查看数据库是否启用了行版本控制功能:
SELECT
name,
is_read_committed_snapshot_on, -- 是否启用 READ COMMITTED SNAPSHOT
snapshot_isolation_state_desc -- 快照隔离是否启用
FROM sys.databases
WHERE name = 'YourDatabaseName';
输出示例:
name | is_read_committed_snapshot_on | snapshot_isolation_state_desc |
---|---|---|
YourDB | 1 | ON |
字段解释:
is_read_committed_snapshot_on:
1 表示启用 READ COMMITTED SNAPSHOT 模式。此时,READ COMMITTED 隔离级别默认使用行版本控制(非锁机制),避免阻塞。
snapshot_isolation_state_desc:
ON 表示启用 SNAPSHOT 隔离级别,允许事务级一致性读取。
READ_COMMITTED_SNAPSHOT:
启用后,所有使用 READ COMMITTED 隔离级别的事务自动使用行版本控制,无需显式设置。
修改此参数需独占数据库连接(需临时设置为单用户模式)。
ALLOW_SNAPSHOT_ISOLATION:
启用后,允许事务使用 SNAPSHOT 隔离级别,但需在会话中显式设置 SET TRANSACTION ISOLATION LEVEL SNAPSHOT。
配置项 | 作用范围 | 影响的隔离级别 | 行为特性 |
---|---|---|---|
READ_COMMITTED_SNAPSHOT | 数据库全局 | READ COMMITTED | 基于行版本控制,非锁机制 |
ALLOW_SNAPSHOT_ISOLATION | 数据库全局 | SNAPSHOT | 事务级快照,完全无锁 |
会话级 SET TRANSACTION | 单个会话/事务 | 任意隔离级别 | 临时覆盖数据库默认行为 |
性能影响:
兼容性:
配置优先级:
总结