SQL 事务有助于将一个或多个语句作为一个整体来执行。如果事务成功,该事务中进行的所有更改都将应用于表。如果事务中的任何单个语句遇到错误,则该事务中进行的更改将被擦除或回滚。
我将向您展示各种示例列表,这些示例可以解释事务。它们包括:BEGIN TRANSACTION、COMMIT TRANSACTION、ROLLBACK TRANSACTION、命名事务、IF ELSE 语句中的事务以及 TRY CATCH 块中的 SQL Server 事务。使用事务时需要记住的事项列表。
- 每个事务都应以 BEGIN TRANSACTION、BEGIN TRAN 或 BEGIN TRANSACTION Transaction_Name 开始
- 每个事务都必须以 COMMIT 或 ROLLBACK 语句之一结束。
- COMMIT TRANSACTION:此语句告诉 SQL 保存 BEGIN 和 COMMIT 之间的更改。有多种方法可以编写此语句。您可以编写 COMMIT、COMMIT TRAN、COMMIT TRANSACTION 或 COMMIT TRANSACTION Transaction_Name
- ROLLBACK TRANSACTION:此语句告诉服务器擦除 BEGIN 和 ROLLBACK 之间的所有更改。有多种方法可以编写此语句。您可以编写 ROLLBACK、ROLLBACK TRAN、ROLLBACK TRANSACTION 或 ROLLBACK TRANSACTION Transaction_Name
SQL Server 事务示例
在此事务示例中,我们将把一个 INSERT INTO SELECT 语句放在 BEGIN 和 COMMIT 事务之间。如您所见,它将从 Employee 表中选择前四条记录,并将它们存储在 Employee Records 表中。
BEGIN TRAN INSERT INTO [dbo].[EmployeeRecords] ( [EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales]) SELECT TOP 4 [EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales] FROM [dbo].[Employee] COMMIT TRANSACTION
运行上述事务查询
Messages
--------
(4 row(s) affected)
让我们查看 Employee Records 表中已插入的行。

SQL Server 中的事务不仅限于单个语句。我们可以在一个事务中放置多个语句。在此 SQL Server 示例中,我们将放入一个 Insert Statement 和一个 Update Statement
BEGIN TRANSACTION
INSERT INTO [dbo].[EmployeeRecords] (
[EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales])
VALUES (5, 'SQL', 'Server', 'Education', 'Teaching', 10000, 200)
UPDATE [dbo].[EmployeeRecords]
SET [Education] = 'Tutorials',
[YearlyIncome] = 98000
WHERE [EmpID] = 5
COMMIT TRANSACTION
在单个事务查询中运行 Insert 和 Update 语句
Messages
--------
(1 row(s) affected)
(1 row(s) affected)
该事务之后 Employee 表中的记录。

SQL 事务中的自动回滚
事务中的语句作为一个整体执行,如果一个语句失败,那么其余语句将不会执行。此过程也称为自动回滚事务。
这次我们将故意使事务中的一个语句失败。如您所见,更新语句将返回错误,因为我们将字符串 (VARCHAR) 信息输入到 float 数据类型中。
BEGIN TRANSACTION
INSERT INTO [dbo].[EmployeeRecords] (
[EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales])
VALUES (6, 'Tutorial', 'Gateway', 'Education', 'Learning', 65000, 1400)
UPDATE [dbo].[EmployeeRecords]
SET [Education] = 'Masters',
[YearlyIncome] = 'Wrong Data'
WHERE [EmpID] = 6
COMMIT TRANSACTION

但是,更新语句中存在错误。我们无法看到已插入的记录,因为它已被服务器回滚。

让我们删除上述代码片段中的 BEGIN TRANSACTION 和 COMMIT TRANSACTION,然后执行这些语句。
INSERT INTO [dbo].[EmployeeRecords] (
[EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales])
VALUES (6, 'Tutorial', 'Gateway', 'Education', 'Learning', 65000, 1400)
UPDATE [dbo].[EmployeeRecords]
SET [Education] = 'Masters',
[YearlyIncome] = 'Wrong Data'
WHERE [EmpID] = 6

我已插入 Emp Id 6 的新记录,但未能更新它。

SQL Server 中的回滚事务
回滚事务可用于将事务回滚到事务的开头或保存点。您可以使用此 SQL 回滚来删除半完成的行或处理错误。
例如,如果您的事务正在插入新记录,但抛出了错误,那么您可以使用此回滚事务将表恢复到原始位置。
在此示例中,我们将向 Employee 表插入一条新记录,并在插入后应用回滚事务。为了演示这一点,我们在事务内部和事务外部使用了 Select Statement。第一个 select 语句将向您显示事务完成之前的表记录。
BEGIN TRANSACTION
INSERT INTO [dbo].[EmployeeRecords] (
[EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales])
VALUES (7, 'SQL Server', 'Tutorial', 'Masters', 'Learn', 55000, 1250)
SELECT * FROM [dbo].[EmployeeRecords]
ROLLBACK TRANSACTION
SELECT * FROM [dbo].[EmployeeRecords]
尽管上述语句没有错误,但它尚未插入记录。

SQL Server 中的命名事务
服务器允许您命名您的事务。当您在一个查询中使用多个事务时,始终建议使用命名事务。
-- AddEmployee is the Transaction name
BEGIN TRANSACTION AddEmployee
INSERT INTO [dbo].[EmployeeRecords] (
[EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales])
VALUES (7, 'SQL Server', 'Tutorial', 'Masters', 'Learn', 55000, 1250)
COMMIT TRANSACTION AddEmployee
SELECT * FROM [dbo].[EmployeeRecords]

IF ELSE 语句中的 SQL 事务
如果我们将事务放在任何条件语句(如 IF ELSE)中,那么事务将更有用。例如,在插入之前检查 employee 表中是否存在记录,如果存在则回滚,否则提交,等等。
以下语句是一个简单的事务示例,其中我们声明了一个变量(假设用户将输入值)。接下来,我们使用 insert 语句,然后在使用 If 语句检查 @sales 是否小于 1000。如果为真,则回滚事务,否则在 Select 语句中提交事务。
DECLARE @Sales FLOAT = 250.0
BEGIN TRANSACTION AddEmployee
INSERT INTO [dbo].[EmployeeRecords] (
[EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales])
VALUES (8, 'Dave', 'Rob', 'High School', 'Professional', 85000, @Sales)
IF @Sales < 1000
BEGIN
ROLLBACK TRANSACTION AddEmployee
PRINT 'Sorry! Sales Amount Should be More than 1000'
END
ELSE
BEGIN
COMMIT TRANSACTION AddEmployee
PRINT 'Inserted the Record Successfully'
END
SELECT * FROM [dbo].[EmployeeRecords]

让我向您展示记录

这次我们更改了变量 @Sales 的值为 1450.02
DECLARE @Sales FLOAT = 1450.02
BEGIN TRANSACTION AddEmployee
INSERT INTO [dbo].[EmployeeRecords] (
[EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales])
VALUES (8, 'Dave', 'Rob', 'High School', 'Professional', 85000, @Sales)
IF @Sales < 1000
BEGIN
ROLLBACK TRANSACTION AddEmployee
PRINT 'Sorry! Sales Amount Should be More than 1000'
END
ELSE
BEGIN
COMMIT TRANSACTION AddEmployee
PRINT 'Inserted the Record Successfully'
END
SELECT * FROM [dbo].[EmployeeRecords]

结果数据在 employee 表中。

TRY CATCH 中的 SQL 事务
如果我们将事务放在 TRY CATCH 块中,那么事务将非常有用。例如,如果事务内部出现错误,那么您可以使用 catch 块将事务回滚到原始位置。
这是一个简单的事务示例,我们将一个 select 语句和一个 update 语句放在事务中。如果您仔细观察,我们的 update 语句将因数据类型冲突而引发错误。
BEGIN TRY BEGIN TRANSACTION AddEmployee INSERT INTO [dbo].[EmployeeRecords] ( [EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales]) VALUES (9, 'Chong', 'Lee', 'Tutorials', 'Developer', 66500, 1950) UPDATE [dbo].[EmployeeRecords] SET [Education] = 'Bachelors', [YearlyIncome] = 'Hey You gotme Wrong!' WHERE [EmpID] = 9 COMMIT TRANSACTION AddEmployee PRINT 'Inserted the Record Successfully' END TRY BEGIN CATCH ROLLBACK TRANSACTION AddEmployee PRINT 'Sorry! There is a Data Type Mismatch for yearly Income' END CATCH SELECT * FROM [dbo].[EmployeeRecords]

并且表中的数据是

让我们将年收入值更改为 91567 并运行事务
BEGIN TRY BEGIN TRANSACTION AddEmployee INSERT INTO [dbo].[EmployeeRecords] ( [EmpID], [FirstName], [LastName], [Education], [Occupation], [YearlyIncome], [Sales]) VALUES (9, 'Chong', 'Lee', 'Tutorials', 'Developer', 66500, 1950) UPDATE [dbo].[EmployeeRecords] SET [Education] = 'Bachelors', [YearlyIncome] = 91567 -- We changed it WHERE [EmpID] = 9 COMMIT TRANSACTION AddEmployee PRINT 'Inserted the Record Successfully' END TRY BEGIN CATCH ROLLBACK TRANSACTION AddEmployee PRINT 'Sorry! There is a Data Type Mismatch for yearly Income' END CATCH SELECT * FROM [dbo].[EmployeeRecords]

并且 Employee 表中的数据是

SQL 事务常见错误
在使用查询中的事务时,常见的一个错误是。如您所见,我们在 BEGIN TRANSACTION 之后使用了一个简单的 Update 语句,但忘记了指定 COMMIT 或 ROLLBACK,
BEGIN TRANSACTION UPDATE [dbo].[EmployeeRecords] SET [YearlyIncome] = 125896 WHERE [EmpID] = 6
Messages
--------
(1 row(s) affected)
让我打开另一个查询窗口(在 SSMS 中单击 New query),然后编写一个简单的 select 语句来选择 Employee Records 表中的所有记录。
请注意,执行时间比平时长。这是因为,默认情况下,Select 语句将返回已提交的数据,而我们忘记了提交更新。

让我将事务隔离级别设置为 Read Uncommitted。它将读取未提交的数据。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED SELECT * FROM [dbo].[EmployeeRecords]
