与 "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
进行基准测试(计时),或以其他方式请求输出。
我正在使用 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
进行基准测试(计时),或以其他方式请求输出。