3

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

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

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

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

4

3 回答 3

7

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

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

于 2011-09-23T19:02:00.773 回答
0

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.

于 2011-09-24T00:42:00.717 回答
-1

在事务中发生某些故障,但事务完成不会是非常事务性的吗?

所以基本上,如果它可能失败并且你不关心它,请不要将它与不能失败的交易放在一起。

使用交易,因为它们应该被使用,你不会有任何问题;)

于 2011-09-23T12:37:41.293 回答