与 "try/catch" 的交易,在 IBM Informix 数据库中回滚

Transaction with "try/catch" with rollback in IBM Informix database

我正在使用 Informix 数据库。我想在事务内部执行一些查询,如果出现错误,我想回滚所有编辑,所以在 SQL Server:

中与此等效
BEGIN TRY
    BEGIN TRAN
        -- insert, update, delete statements etc.
    COMMIT TRAN
END TRY
BEGIN CATCH
    IF(@@TRANCOUNT > 0)
        ROLLBACK TRAN;
END CATCH

这里是 Informix syntax for a transaction:

BEGIN WORK;
    -- statements
COMMIT WORK;

当我搜索“informix try catch”时,我得到的第一个 link 是关于 "On Exception",但是,没有页面显示有关如何捕获异常的语法的完整示例和回滚,我在互联网上的任何地方都找不到这样的例子。我尝试执行以下查询:

begin work;
    create table test_abc
    (
        test_value int
    );
    on exception
        rollback work;
    end exception
commit work;

我的预期是该查询第一次可以运行,但第二次会失败,因为 table 已经存在。但是,我第一次收到此错误:

begin work;
        create table test_abc
        (
                test_value int
        );
        on exception
#^
#  201: A syntax error has occurred.
#
                rollback work;
        end exception
commit work;

所以语法无效。

正确的语法是什么?


编辑:关于我在做什么的更多信息。我有一项新任务,我需要为此添加一些新的 table 并在其中一些中放入几行。尽管可以在所有环境(测试、产品等)上一次(或一条一条地)简单地执行所有语句,但我希望我可以将所有语句打包在一个事务中,以避免在出现问题时不得不清理. Jonathan Leffler 建议创建存储过程并使用 on exception 处理异常捕获,但我只需要使用 1 次事务,这不保证创建存储过程。从技术上讲,我可以使用事务创建存储过程,运行 它并删除它,但是如果有一种方法可以避免必须创建存储过程,那么知道如何操作会很高兴。

SPL(存储过程语言)中的异常处理

由于 ON EXCEPTION 是可能的,我假设您正在使用存储过程。

您的示例是正确的,但是错放了异常处理代码:

-- incorrect code from question
begin work;
    create table test_abc
    (
        test_value int
    );
    on exception
        rollback work;
    end exception
commit work;

您需要在可能产生异常的代码之前指定异常处理。一个更接近正确的代码片段是:

CREATE PROCEDURE make_test_abc()
    BEGIN WORK;
    BEGIN
    ON EXCEPTION
        ROLLBACK WORK;
    END EXCEPTION;
    CREATE TABLE test_abc
    (   
        test_value INT 
    );  
    COMMIT WORK;
    END;
END PROCEDURE;

EXECUTE PROCEDURE make_test_abc();

上面的符号有效;多个类似版本不起作用。 SPL 有时会变得非常复杂。

我的库中还有一个 'transaction state' 函数,它使用 ON EXCEPTION:

CREATE PROCEDURE tx_state() RETURNING VARCHAR(14);
    DEFINE errcode INTEGER;
    ON EXCEPTION IN (-256, -535) SET errcode
        IF errcode = -256 THEN
            RETURN "TX-Unavailable";
        ELIF errcode = -535 THEN
            RETURN "In-TX";
        END IF;
    END EXCEPTION
    BEGIN WORK;
    ROLLBACK WORK;
    RETURN "No-TX";
END PROCEDURE

如今,table创作练习也有替代机制:

DROP TABLE IF EXISTS test_abc;
CREATE TABLE IF NOT EXISTS test_abc(test_value INT);

存在用于创建和删除过程的类似选项:

DROP PROCEDURE IF EXISTS make_test_abc;
CREATE PROCEDURE IF NOT EXISTS make_test_abc()
…
END PROCEDURE;
CREATE OR REPLACE PROCEDURE make_test_abc()
…
END PROCEDURE;

这两个变体 CREATE PROCEDURE 语句与 Informix 以外的不同 DBMS 兼容。 OR REPLACE 选项需要 14.10 版本(以及更新的版本之一;我认为它在 14.10.FC1 中不可用)。 EXISTS 选项在 12.10 中也可用(但同样,不一定在旧的 12.10 版本中)。

即使使用 IF [NOT] EXISTS 子句(或 OR REPLACE 子句),如果您没有相关权限,操作当然也会失败。

但是,我假设这个问题比如何无例外地创建 table 更笼统。这应该会给你一些指导。除了 SPL(存储过程语言)外,ON EXCEPTION 子句不可用,这意味着它只能在 CREATE PROCEDURE(或 CREATE FUNCTION)语句中使用。


正在执行语句并且在失败时不提交

如果您使用 DB-Access 执行一系列命令,您可以使用大纲创建脚本(称之为 script.sql):

BEGIN WORK;

CREATE …
DROP …
CREATE …
GRANT …
…

COMMIT WORK;

然后您可以 运行 在环境中设置环境变量 DBACCNOIGN(DB-Access“无忽略错误”)以批处理模式。

$ DBACCNOIGN=1 dbaccess yourdb script
…voluble output — some to standard output, some to standard error…
$

语句成功时会有输出,但如果失败,脚本将停止并回滚事务。如果语句全部成功,将执行 COMMIT WORK 并提交事务。

此外,请考虑检查 SQLCMD(可从 IIUG Software Archive 获得),我编写的它在 DB-Access 不支持的 shell 脚本上下文中表现一致。它可以追溯到 1986 年(在 dbaccess 之前;在那些日子里,您使用 isql 代替 — DB-Access 是在一个晚上从 isql 中分割出来的)。它与 Microsoft 的同名 johnny-come-lately 程序没有任何关系——除了名称和具有相同的通用目的(操纵 SQL 数据库)。与 DB-Access 不同,SQLCMD 不会在出现错误时继续执行,除非您告诉它这样做(-c 命令行选项,或脚本文件中的 continue on;)。

$ sqlcmd -d yourdb -f script.sql
$

与 DB-Access 不同,SQLCMD 不会有任何输出,除非您遇到错误,或 select 某些东西,或使用 -x 请求它(跟踪) 选项或 -v (详细)选项,或要求使用 -B 进行基准测试(计时),或以其他方式请求输出。