命令失败后 Npgsql 不提交事务

发布于 2024-12-05 20:34:58 字数 347 浏览 1 评论 0原文

我在.NET 4.0 下使用 Npgsql 2.0.11 来修改 PostgreSQL 9.0 数据库。该程序对数据库进行了许多修改,所有这些修改都在一个事务中完成。

就在提交之前,我运行 SELECT 语句,该语句有时会失败(例如超时)。我接受了异常并继续提交事务。没有错误,所以看起来好像一切正​​常,但实际上数据库根本没有修改!

我的猜测是失败的 SELECT 回滚了整个事务。我可以阻止这种情况(即仍然提交事务)或者至少检测到这种情况并抛出异常,以便用户知道提交失败吗?

我知道在这种特定情况下,我可以将 SELECT 移到事务之外,但我更关心如何解决一般情况下的问题。提交未提交是一个非常严重的问题,我想确保它不会被发现。

I'm using Npgsql 2.0.11 under .NET 4.0 to modify a PostgreSQL 9.0 database. The program makes many modifications to the database, all within a single transaction.

Just before committing, I run SELECT statement, which sometimes fails (eg. with a timeout). I swallow the exception and go ahead and commit the transaction anyway. There is no error, so it appears as if everything worked, but in actual fact the database was not modified at all!

My guess is that the failed SELECT rolled back the entire transaction. Can I either prevent this (ie. have the transaction still committed) or at least detect this situation and throw an exception, so the user knows the commit failed?

I know that in this specific case I could just move the SELECT outside the transaction, but I'm more concerned about solving this for the general case. Having a commit not commit is a pretty serious problem and I want to make sure it doesn't go undetected.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

木落 2024-12-12 20:34:58

我对 Npgsql 一无所知,但我可以谈论 PostgreSQL 的行为。当 PostgreSQL 事务中发生任何错误时,该事务将被标记为“无效”,直到关闭为止。 (他们的术语是“中止”,我认为这是误导性的。)此外,恕我直言,这是疯狂的,如果您COMMIT一个无效的交易,它会“成功”,但与具有相同的效果回滚。您可以在 psql REPL 中观察到这一点;它会打印 ROLLBACK 来响应您的 COMMIT 命令,但不会发出错误信号。

您可以在最终 SELECT 之前创建一个 SAVEPOINT。如果失败,则ROLLBACK到保存点名称;这将使您摆脱无效状态并允许您提交事务的前一部分。

I know nothing about Npgsql, but I can speak to the behavior of PostgreSQL. When any error occurs within a PostgreSQL transaction, the transaction is marked invalid until it is closed. (Their term is "aborted", which I think is misleading.) Furthermore, and this is IMHO insane, if you COMMIT an invalid transaction, it "succeeds" but has the same effect as ROLLBACK. You can observe this in the psql REPL; it will print ROLLBACK in response to your COMMIT command, but it won't signal an error.

You can create a SAVEPOINT right before your final SELECT. If it fails, then ROLLBACK to the savepoint name; that will get you out of the invalid state and allow you to commit the previous part of the transaction.

南渊 2024-12-12 20:34:58

我最终编写了一个小包装方法,尝试在提交之前执行一个简单的语句作为事务的一部分,这对于检测问题很有效。

    public static void CommitTransaction(NpgsqlConnection conn, NpgsqlTransaction tran)
    {
        using (var command = new NpgsqlCommand("SELECT 1", conn, tran))
        {
            try
            {
                command.ExecuteScalar();
            }
            catch (NpgsqlException ex)
            {
                if (ex.Code == "25P02")
                    throw new Exception("The transaction is invalid...");
                throw;
            }
        }

        tran.Commit();
    }

解决方法是 Morg.Ryan Culpepper 的答案:要么在事务外部运行该语句,要么预先创建一个 SAVEPOINT 并在出错时回滚到它。

I ended up writing a little wrapper method that tries to execute a trivial statement as part of the transaction right before committing, which is effective in detecting the problem.

    public static void CommitTransaction(NpgsqlConnection conn, NpgsqlTransaction tran)
    {
        using (var command = new NpgsqlCommand("SELECT 1", conn, tran))
        {
            try
            {
                command.ExecuteScalar();
            }
            catch (NpgsqlException ex)
            {
                if (ex.Code == "25P02")
                    throw new Exception("The transaction is invalid...");
                throw;
            }
        }

        tran.Commit();
    }

The fix is either of Morg.'s or Ryan Culpepper's answers: either run the statement outside of the transaction or create a SAVEPOINT beforehand and ROLLBACK to it on error.

梦里兽 2024-12-12 20:34:58

如果事务中出现某些问题但事务已完成,那么事务性就不会很高,对吗?

所以基本上,如果它可能会失败并且您不关心它,请不要将其与一定不会失败的事务一起放入事务中。

按照交易的用途使用交易,您不会遇到任何问题;)

Having something fail within a transaction and yet the transaction complete wouldn't be very transactional right ?

So basically, if it may fail and you don't care about it, don't put it in the transaction with that which must not fail.

Use transactions as they're meant to be used and you won't have any issues ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文