如何以编程方式知道回滚事务(可以在SQL Server中执行,但需要oracle解决方案)

时间:2009-07-01 18:40:56

标签: sql sql-server oracle transactions

这似乎应该是我已经知道的东西。我们需要在事务中运行一堆sql更新,如果其中一个失败则回滚。我们还想打印状态消息,因为我们将运行大量这些消息。如果我使用通用编程语言,这将很简单。但我试图找到一个团队成员可以使用的解决方案,这只是SQL。她过去使用下面的模式在MS SQL Server中完成了这项工作。 Oracle有一个等效的简单模式吗?

DECLARE @ErrorVar INT;
BEGIN TRANSACTION;
UPDATE MyTable1 SET MyColumn1 = 'JSMITH' where MyColumn1 = 'JOHN';
SET @ErrorVar = @@ERROR;
UPDATE MyTable2 SET MyColumn2 = 'JSMITH' where MyColumn2 = 'JOHN';
SET @ErrorVar = @ErrorVar + @@ERROR;
UPDATE MyTable SET LoginID = 'JSMITH' where LoginID = 'JOHN';
SET @ErrorVar = @ErrorVar + @@ERROR;

IF @ErrorVar <> 0
   BEGIN
   ROLLBACK TRANSACTION;
   PRINT 'We had a problem with JSMITH and rolled back *****';
   END;
ELSE
   BEGIN
   COMMIT TRANSACTION;
   PRINT 'JSMITH Updated ok';
   END;
GO

6 个答案:

答案 0 :(得分:7)

在SQLPlus中,使用WHENEVER命令控制发生错误时的行为。

WHERVER SQLERROR EXIT FAILURE ROLLBACK在我们的脚本中是相当标准的。

在SQLPlus提示符下键入HELP WHENEVER以获取更多信息。

答案 1 :(得分:2)

因为我对akf评论的回答太长而无法发表评论,所以我将其作为单独的答案发布。

这就是为什么它没有实现任何额外/有用的原因。

假设我们有Peter提到的三个表:

SQL> create table mytable1 (mycolumn1) as select cast('JOHN' as varchar2(6)) from dual
  2  /

Tabel is aangemaakt.

SQL> create table mytable2 (mycolumn2) as select cast('JOHN' as varchar2(6)) from dual
  2  /

Tabel is aangemaakt.

SQL> create table mytable (loginid) as select cast('JOHN' as varchar2(6)) from dual
  2  /

Tabel is aangemaakt.

并添加一个检查约束以使第三个更新语句失败:

SQL> alter table mytable add constraint no_jsmith_ck1 check (loginid <> 'JSMITH')
  2  /

Tabel is gewijzigd.

PL / SQL块可以像这样简单,但它失败了:

SQL> begin
  2    update mytable1
  3       set mycolumn1 = 'JSMITH'
  4     where mycolumn1 = 'JOHN'
  5    ;
  6    update mytable2
  7       set mycolumn2 = 'JSMITH'
  8     where mycolumn2 = 'JOHN'
  9    ;
 10    update mytable
 11       set loginid = 'JSMITH'
 12     where loginid = 'JOHN'
 13    ;
 14    commit
 15    ;
 16  end;
 17  /
begin
*
FOUT in regel 1:
.ORA-02290: check constraint (RWK.NO_JSMITH_CK1) violated
ORA-06512: at line 10

并显示所有内容都已回滚,而不发送回滚:

SQL> select * from mytable1
  2  /

MYCOLU
------
JOHN

1 rij is geselecteerd.

SQL> select * from mytable2
  2  /

MYCOLU
------
JOHN

1 rij is geselecteerd.

SQL> select * from mytable
  2  /

LOGINI
------
JOHN

1 rij is geselecteerd.

因此这里不需要异常处理程序。您建议的异常处理程序执行此操作:

SQL> begin
  2    update mytable1
  3       set mycolumn1 = 'JSMITH'
  4     where mycolumn1 = 'JOHN'
  5    ;
  6    update mytable2
  7       set mycolumn2 = 'JSMITH'
  8     where mycolumn2 = 'JOHN'
  9    ;
 10    update mytable
 11       set loginid = 'JSMITH'
 12     where loginid = 'JOHN'
 13    ;
 14    commit
 15    ;
 16  EXCEPTION
 17  WHEN OTHERS THEN
 18    ROLLBACK;  --// Oracle will do this for you, but it doesnt hurt to be clear
 19    DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_backtrace);
 20    raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR-     '||SQLERRM);
 21  END;
 22  /
ORA-06512: at line 10

begin
*
FOUT in regel 1:
.ORA-20001: An error was encountered - -2290 -ERROR-     ORA-02290: check constraint (RWK.NO_JSMITH_CK1) violated
ORA-06512: at line 20

虽然没有错,但我在这里看不出任何增值。

SQL> select * from mytable1
  2  /

MYCOLU
------
JOHN

1 rij is geselecteerd.

SQL> select * from mytable2
  2  /

MYCOLU
------
JOHN

1 rij is geselecteerd.

SQL> select * from mytable
  2  /

LOGINI
------
JOHN

1 rij is geselecteerd.

为什么建议添加无效的代码?

此致 罗布。

答案 2 :(得分:1)

您可以在程序结束时添加EXCEPTION块:

EXCEPTION
WHEN OTHERS THEN
  ROLLBACK;  --// Oracle will do this for you, but it doesnt hurt to be clear
  DBMS_OUTPUT.put_line (DBMS_UTILITY.format_error_backtrace);
  raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR-     '||SQLERRM);
END;

修改 我添加了一个调用来输出回溯以在错误报告中提供亚麻布。 (这是10克或更好)

答案 3 :(得分:1)

PL / SQL具有回滚和回滚到保存点命令。

您可以找到有关它的文档here

答案 4 :(得分:1)

一个简单的SQL脚本可能看起来像这样:

set serveroutput on
DECLARE
BEGIN
  dbms_output.enable(100000);  -- overrides default 10000 byte limit
  UPDATE MyTable1 SET MyColumn1 = 'JSMITH' where MyColumn1 = 'JOHN';
  UPDATE MyTable2 SET MyColumn2 = 'JSMITH' where MyColumn2 = 'JOHN';
  UPDATE MyTable SET LoginID = 'JSMITH' where LoginID = 'JOHN';
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
     ROLLBACK;
     dbms_output.put_line('Error processing JSMITH');
END;
/

这在Oracle中称为匿名过程。您可以通过sqlplus轻松地将其提供给Oracle:

sqlplus user/pw@db @yourscript

当然,您可以通过脚本获得更好的功能(例如,使用BEGIN-EXCEPTION-END包围每个更新以确定哪个更新有问题)但这应该可以帮助您入门。

答案 5 :(得分:0)

如果存储过程是您的设计选择(我不确定),那么您可能希望执行类似下面的操作:

EXCEPTION
    WHEN OTHERS
    THEN
      out_status := 1;
      raise_application_error(-20001,SQLERRM);
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
  END;

如果您要查找的所有内容都是通过/失败布尔值,那么从存储过程中返回out状态将允许您做出相应的响应。

如果您选择直接SQL,那么在ORACLE中如果在sql语句更新期间遇到异常,它将抛出异常而不提交任何更改(我不确定当更新未成功时需要回滚一个例外,我相信Oracle会处理这个问题。)