异常块中的事务 - 如何?

Posted

技术标签:

【中文标题】异常块中的事务 - 如何?【英文标题】:Transaction in an exception block - how? 【发布时间】:2017-02-02 11:04:11 【问题描述】:

请哪位好心的人指出这是错误的地方吗? 我正在尝试运行一个非常简单的事务测试,但甚至无法运行该语句。我正在尝试在 PG Admin 的 SQL Query 窗口中运行它。没有其他与数据库的连接。

DO $$
BEGIN

START TRANSACTION;

UPDATE IsolationTests SET Col1 = 2;
perform pg_sleep(5.0);

ROLLBACK;

EXCEPTION WHEN division_by_zero THEN
BEGIN
END;

END $$;

我想玩转事务级别并在代码中开始和结束事务。如果我注释掉“开始交易”和“回滚”,则语句运行良好。取消注释它们,我得到了

"ERROR:  cannot begin/end transactions in PL/pgSQL
HINT:  Use a BEGIN block with an EXCEPTION clause instead."

嗯?它在 BEGIN ... EXCEPTION 块中,不是吗??

【问题讨论】:

在 PL/pgSQL BEGIN ... END不是关于事务的。这是一个语法块。就像 Java 或 C++ 中的 ... 一样,DO 块是一个匿名函数,您不能在 Postgres(或 SQL Server 中)的函数中进行事务控制。不幸的是 Postgres 没有存储过程,所以你总是需要在调用代码中管理事务 它不喜欢 PlPgSql 中的START TRANSACTION;,不在异常块中开始 @a_horse_with_no_name - 好的,谢谢。为了确保我清楚这一点:唯一的方法是使用 C# 库打开连接,在该连接上发出“开始事务”语句,然后在终止连接之前发出“回滚”或“提交”? 基本上是的。如果我没记错的话,你可以在函数中拥有的唯一“事务控制”是保存点 【参考方案1】:

回答您的问题 - 指出这是错误的地方:START TRANSACTION; 而不是 EXCEPTION 块中的 BEGIN 语句...

我不确定你想做什么。这是回滚事务的示例(表 t 已创建,但未提交 => 不存在),但异常 (/0) 已捕获并已处理(引发的信息):

t=# begin;
BEGIN
Time: 0.124 ms
t=#
t=# DO $$
t$# BEGIN
t$#   begin
t$#     create table t (i int);
t$#   end;
t$#     perform 1/0;
t$# EXCEPTION WHEN division_by_zero THEN
t$#   BEGIN
t$#     raise info '%','exc catched';
t$#   END;
t$#
t$# END;
t$# $$
t-# ;
INFO:  exc catched
DO
Time: 10.288 ms
t=#
t=# rollback;
ROLLBACK
Time: 0.152 ms
t=#
t=# \dt+ t
No matching relations found.
t=# ;
Time: 0.062 ms

【讨论】:

感谢您的回复,Vao。我认为 a_horse_with_no_name 已经回答了我的问题。

以上是关于异常块中的事务 - 如何?的主要内容,如果未能解决你的问题,请参考以下文章

如何跳过嵌套块中的异常

检查 PL/SQL 异常块中的特定错误代码

如何使用多个catch块处理异常

如何在 Ruby 的 MULTI 块中读取 Redis?

finally 块中的异常

数据块中的异常处理