今天我们来深入探讨SQL Server中非常重要的话题——事务处理。掌握事务处理,让你的数据操作更加安全可靠!
一、什么是事务?
事务是单个的工作单元。如果某一事务成功,则在该事务中进行的所有数据更改均会提交,成为数据库中的永久组成部分。如果事务遇到错误且必须取消或回滚,则所有数据更改均被清除。
简单理解:事务就像银行转账,要么同时成功(扣款+存款),要么同时失败,不会出现扣了钱但没到账的情况。
二、事务的三种运行模式
1. 自动提交事务
每条单独的语句都是一个事务。这是SQL Server的默认模式。
INSERT INTO users VALUES ('张三', 25)UPDATE users SET age = 26 WHERE name = '张三'
2. 显式事务
每个事务均以BEGIN TRANSACTION显式开始,以COMMIT或ROLLBACK显式结束。
BEGIN TRANSACTION UPDATE account SET balance = balance - 100 WHERE id = 1 UPDATE account SET balance = balance + 100 WHERE id = 2COMMIT TRANSACTION
3. 隐性事务
在前一个事务完成时,新事务隐式启动,但每个事务仍以COMMIT或ROLLBACK显式完成
SET IMPLICIT_TRANSACTIONS ON
INSERT INTO users VALUES ('李四', 30)UPDATE users SET age = 31 WHERE name = '李四'COMMIT TRANSACTION
DELETE FROM users WHERE name = '李四'ROLLBACK TRANSACTION
三、事务操作核心语法
1. BEGIN TRANSACTION - 开始事务
标记一个显式本地事务的起始点,将@@TRANCOUNT加1。
BEGIN TRAN [SACTION] [transaction_name | @tran_name_variable]
BEGIN TRAN T1 UPDATE table1 SET col1 = 'value1'
BEGIN TRAN M2 WITH MARK '标记说明' UPDATE table2 SET col2 = 'value2' SELECT * FROM table1 COMMIT TRAN M2
UPDATE table3 SET col3 = 'value3'COMMIT TRAN T1
2. BEGIN DISTRIBUTED TRANSACTION - 分布式事务
指定由MS DTC管理的分布式事务的起始。
BEGIN DISTRIBUTED TRANSACTION UPDATE authors SET au_lname = 'McDonald' WHERE au_id = '409-56-7008'
EXECUTE link_Server_T.pubs.dbo.changeauth_lname '409-56-7008', 'McDonald'COMMIT TRAN
注意:需要安装MS DTC,且链接服务器的RPC选项必须设为True。
3. SET XACT_ABORT - 错误处理设置
指定当产生运行时错误时,是否自动回滚当前事务
SET XACT_ABORT OFFBEGIN TRAN INSERT INTO t2 VALUES (1) INSERT INTO t2 VALUES (2) INSERT INTO t2 VALUES (3) COMMIT TRAN
SET XACT_ABORT ONBEGIN TRAN INSERT INTO t2 VALUES (4) INSERT INTO t2 VALUES (5) INSERT INTO t2 VALUES (6) COMMIT TRAN
4. SAVE TRANSACTION - 设置保存点
在事务内设置保存点,可以有条件地取消事务的一部分。
BEGIN TRANSACTION SAVE TRANSACTION A
INSERT INTO demo VALUES('BB', 'B term')
ROLLBACK TRANSACTION A
CREATE TABLE demo2 (name varchar(10), age int) INSERT INTO demo2 VALUES('lis', 1)
COMMIT TRANSACTION
5. ROLLBACK TRANSACTION - 回滚事务
将事务回滚到起点或某个保存点。
BEGIN TRANSACTION INSERT INTO users VALUES ('王五', 28) UPDATE users SET age = 29 WHERE name = '王五'ROLLBACK TRANSACTION
BEGIN TRANSACTION INSERT INTO users VALUES ('赵六', 22) SAVE TRANSATION SavePoint1 INSERT INTO users VALUES ('钱七', 24) ROLLBACK TRANSACTION SavePoint1 COMMIT TRANSACTION
6. COMMIT TRANSACTION - 提交事务
标志一个成功的事务结束,使修改成为数据库的永久部分。
BEGIN TRANSACTION A INSERT INTO demo VALUES('BB', 'B term')COMMIT TRANSACTION A
四、嵌套事务处理
SQL Server中的嵌套事务将内部事务合并到外部事务中
BEGIN TRAN t1 INSERT INTO demo2 VALUES('lis', 1)
BEGIN TRAN t2 INSERT INTO demo VALUES('BB', 'B term') ROLLBACK TRAN t2
INSERT INTO demo2 VALUES('lis', 2)COMMIT TRAN t1
BEGIN TRAN t1 INSERT INTO demo2 VALUES('lis', 1)
BEGIN TRAN t2 INSERT INTO demo VALUES('BB', 'B term') COMMIT TRAN t2
INSERT INTO demo2 VALUES('lis', 2)COMMIT TRAN t1
五、事务隔离级别
设置锁超时
SET LOCK_TIMEOUT 5000
SET LOCK_TIMEOUT 0
SET LOCK_TIMEOUT -1
五种隔离级别
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
六、实际应用场景
场景1:银行转账(原子性保证)
BEGIN TRY BEGIN TRANSACTION
DECLARE @balance DECIMAL(10,2) SELECT @balance = balance FROM accounts WHERE account_id = 1001 AND account_status = 'ACTIVE'
IF @balance < 1000 THROW 50000, '余额不足', 1
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1001
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 1002
INSERT INTO transaction_log (from_account, to_account, amount, trans_time) VALUES (1001, 1002, 1000, GETDATE())
COMMIT TRANSACTION PRINT '转账成功'END TRYBEGIN CATCH ROLLBACK TRANSACTION PRINT '转账失败:' + ERROR_MESSAGE()END CATCH
场景2:订单处理(一致性保证)
BEGIN TRANSACTION SAVE TRANSACTION OrderCreate
INSERT INTO orders (order_no, customer_id, order_date, total_amount) VALUES ('ORD2024001', 101, GETDATE(), 299.00)
DECLARE @order_id INT = SCOPE_IDENTITY()
INSERT INTO order_details (order_id, product_id, quantity, price) VALUES (@order_id, 1001, 2, 99.50)
IF NOT EXISTS ( SELECT 1 FROM inventory WHERE product_id = 1001 AND quantity >= 2 ) BEGIN ROLLBACK TRANSACTION OrderCreate PRINT '库存不足,订单创建失败' RETURN END
UPDATE inventory SET quantity = quantity - 2 WHERE product_id = 1001
COMMIT TRANSACTIONPRINT '订单创建成功'
场景3:分布式事务(跨数据库操作
BEGIN DISTRIBUTED TRANSACTION
UPDATE LocalDB.dbo.Products SET Stock = Stock - 5 WHERE ProductID = 101
EXEC RemoteDB.warehouse.dbo.sp_UpdateStock @ProductID = 101, @Quantity = -5
COMMIT TRANSACTION
七、事务最佳实践
1. 事务设计原则
保持简短:事务越短,锁定资源的时间越少
避免用户交互:不要在事务中等待用户输入
合理使用隔离级别:根据业务需求选择适当级别
2. 错误处理模板
SET XACT_ABORT ON SET NOCOUNT ON
BEGIN TRY BEGIN TRANSACTION
COMMIT TRANSACTIONEND TRYBEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION
INSERT INTO ErrorLog (ErrorMessage, ErrorSeverity, ErrorTime) VALUES (ERROR_MESSAGE(), ERROR_SEVERITY(), GETDATE())
THROW END CATCH
3. 死锁预防
按相同顺序访问资源
使用较低的隔离级别
考虑使用行版本控制隔离级别
设置合理的锁超时时间
八、常见问题解答
Q1:事务嵌套时,@@TRANCOUNT的值如何变化?
A:每进入一个BEGIN TRANSACTION,@@TRANCOUNT增加1;每执行一个COMMIT,减少1;ROLLBACK会将@@TRANCOUNT置为0。
Q2:如何在事务中查看当前事务层数?
A:使用SELECT @@TRANCOUNT查看当前嵌套层级。
Q3:保存点有什么限制?
A:分布式事务中不支持保存点;回滚到保存点不会释放锁。
总结
事务是保证数据一致性的重要机制,合理使用事务能够:
✅ 保证数据的原子性(Atomicity)
✅ 维护数据的一致性(Consistency)
✅ 实现操作的隔离性(Isolation)
✅ 确保修改的持久性(Durability)
掌握事务处理,让你的数据库操作更加专业可靠!
阅读原文:原文链接
该文章在 2026/4/15 18:15:32 编辑过