命令失败后 Npgsql 不提交事务
我在.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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我对 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 asROLLBACK
. You can observe this in thepsql
REPL; it will printROLLBACK
in response to yourCOMMIT
command, but it won't signal an error.You can create a
SAVEPOINT
right before your finalSELECT
. If it fails, thenROLLBACK
to the savepoint name; that will get you out of the invalid state and allow you to commit the previous part of the transaction.我最终编写了一个小包装方法,尝试在提交之前执行一个简单的语句作为事务的一部分,这对于检测问题很有效。
解决方法是 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.
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.
如果事务中出现某些问题但事务已完成,那么事务性就不会很高,对吗?
所以基本上,如果它可能会失败并且您不关心它,请不要将其与一定不会失败的事务一起放入事务中。
按照交易的用途使用交易,您不会遇到任何问题;)
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 ;)