【问题标题】:applying sql transactions on non consecutive steps在非连续步骤上应用 sql 事务
【发布时间】:2015-04-02 05:36:29
【问题描述】:
我有以下SQL语句场景:
DELETE FROM T1
DELETE FROM T2
DELETE FROM T3
DELETE FROM T4
DELETE FROM T5
在上述情况下我需要实现:
如果下一条 SQL 语句失败,则会回滚上一条语句,如果成功则移动到下一条语句。
但是对于第 5 步,我需要回滚第 3 步,按原样提交第 4 步。
任何意见,请多多指教。
【问题讨论】:
标签:
sql
sql-server
sql-server-2008
tsql
transactions
【解决方案1】:
在 SQL Server 中,没有嵌套事务之类的东西。但是您可以通过一些错误处理编排来做到这一点。
此示例代码只是在 T5 命令遇到错误的情况下再次从 T4 重新发出删除命令。
SET NOCOUNT ON;
-- (use temp table, since table vars do not participate in transactions)
CREATE TABLE #T1(C int);
CREATE TABLE #T2(C int);
CREATE TABLE #T3(C int);
CREATE TABLE #T4(C int);
CREATE TABLE #T5(C int);
INSERT INTO #T1 SELECT 1;
INSERT INTO #T2 SELECT 1;
INSERT INTO #T3 SELECT 1;
INSERT INTO #T4 SELECT 1;
INSERT INTO #T5 SELECT 1;
BEGIN TRY
BEGIN TRAN TR1;
DELETE FROM #T1;
DELETE FROM #T2;
DELETE FROM #T3;
DELETE FROM #T4;
--select 1/0 as 'forced error @ stage1';
END TRY
BEGIN CATCH
PRINT 'error @stage1';
PRINT 'rollback @stage1';
ROLLBACK TRAN TR1;
RETURN;
END CATCH
BEGIN TRY
DELETE FROM #T5;
select 1/0 as 'forced error @stage2';
COMMIT TRAN TR1;
END TRY
BEGIN CATCH
PRINT 'error @stage2';
ROLLBACK TRAN TR1;
BEGIN TRY
print 'redo delete T4'
BEGIN TRAN TR2;
DELETE FROM #t4;
--select 1/0 as 'forced error @redo delete';
COMMIT TRAN TR2;
END TRY
BEGIN CATCH
ROLLBACK TRAN TR2;
PRINT 'second chance delete from T4 failed';
END CATCH
END CATCH
select count(*) as count,'T1' as 'table' from #T1
union all
select count(*) as count,'T2' as 'table' from #T2
union all
select count(*) as count,'T3' as 'table' from #T3
union all
select count(*) as count,'T4' as 'table' from #T4
union all
select count(*) as count,'T5' as 'table' from #T5
DROP TABLE #T1;
DROP TABLE #T2;
DROP TABLE #T3;
DROP TABLE #T4;
DROP TABLE #T5;
【解决方案2】:
您可以在 TRY-CATCH 块中使用 SAVE POINTS 和 GOTO:
这可以实现您在问题中想要的两个目标:
每次使用取消注释特定的“SELECT 1/0”语句来测试它:
SET NOCOUNT ON;
CREATE TABLE #T1(ID int);
CREATE TABLE #T2(ID int);
CREATE TABLE #T3(ID int);
CREATE TABLE #T4(ID int);
CREATE TABLE #T5(ID int);
INSERT INTO #T1 SELECT 1;
INSERT INTO #T2 SELECT 1;
INSERT INTO #T3 SELECT 1;
INSERT INTO #T4 SELECT 1;
INSERT INTO #T5 SELECT 1;
BEGIN TRAN
BEGIN TRY
DELETE FROM #T1
--SELECT 1/0
END TRY
BEGIN CATCH
ROLLBACK TRAN
GOTO LAST2
END CATCH
SAVE TRAN pice1
BEGIN TRY
DELETE FROM #T2
--SELECT 1/0
END TRY
BEGIN CATCH
ROLLBACK TRAN
GOTO LAST2
END CATCH
SAVE TRAN pice2
BEGIN TRY
DELETE FROM #T3
--SELECT 1/0
END TRY
BEGIN CATCH
ROLLBACK TRAN pice1
GOTO LAST
END CATCH
SAVE TRAN pice3
BEGIN TRY
DELETE FROM #T4
--SELECT 1/0
END TRY
BEGIN CATCH
ROLLBACK TRAN pice2
GOTO LAST
END CATCH
SAVE TRAN pice4
BEGIN TRY
DELETE FROM #T5
SELECT 1/0
END TRY
BEGIN CATCH
ROLLBACK TRAN pice2
DELETE FROM #T4
GOTO LAST
END CATCH
LAST:
COMMIT TRAN
LAST2:
SELECT COUNT(*) CT,'T1' [TABLE] FROM #T1
UNION
SELECT COUNT(*) CT,'T2' [TABLE] FROM #T2
UNION
SELECT COUNT(*) CT,'T3' [TABLE] FROM #T3
UNION
SELECT COUNT(*) CT,'T4' [TABLE] FROM #T4
UNION
SELECT COUNT(*) CT,'T5' [TABLE] FROM #T5
DROP TABLE #T1;
DROP TABLE #T2;
DROP TABLE #T3;
DROP TABLE #T4;
DROP TABLE #T5;