PSQLException:当前事务中止,命令被忽略,直到事务块结束


151

我在JBoss 7.1.1 Final的server.log文件中看到以下(截断的)堆栈跟踪:

Caused by: org.postgresql.util.PSQLException: 
ERROR: current transaction is aborted, commands ignored until end of 
transaction block

at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:374)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:302)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_23]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_23]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_23]
at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_23]
at org.postgresql.ds.jdbc23.AbstractJdbc23PooledConnection$StatementHandler.invoke(AbstractJdbc23PooledConnection.java:455)
at $Proxy49.executeUpdate(Unknown Source)   at org.jboss.jca.adapters.jdbc.WrappedStatement.executeUpdate(WrappedStatement.java:371)
at org.infinispan.loaders.jdbc.TableManipulation.executeUpdateSql(TableManipulation.java:154) [infinispan-cachestore-jdbc-5.1.2.FINAL.jar:5.1.2.FINAL]
... 154 more

检查Postgres日志文件将显示以下语句:

STATEMENT:  SELECT count(*) FROM ISPN_MIXED_BINARY_TABLE_configCache
ERROR:  current transaction is aborted, commands ignored until end of transaction block
STATEMENT:  CREATE TABLE ISPN_MIXED_BINARY_TABLE_configCache(ID_COLUMN VARCHAR(255) NOT NULL, DATA_COLUMN BYTEA, TIMESTAMP_COLUMN BIGINT, PRIMARY KEY (ID_COLUMN))
ERROR:  relation "ispn_mixed_binary_table_configcache" does not exist at character 22

我正在使用JBoss 7.1.1 Final(即5.1.2.Final)附带的Infinispan。

所以这就是我正在发生的事情:

  • Infinispan尝试运行该SELECT count(*)...语句,以查看;中是否有任何记录ISPN_MIXED_BINARY_TABLE_configCache
  • 由于某种原因,Postgres不喜欢此声明。
  • Infinispan对此不予理and,并在CREATE TABLE声明中坚持不懈。
  • Postgres f之以鼻,因为它仍然认为这是同一笔交易,而Infinispan未能回滚,而该笔交易是从第一个SELECT count(*)...语句开始的。

此错误是什么意思,以及如何解决该错误的任何想法?


就算您像我这样来这里寻找以上PSQLException: current transaction is aborted...25P02),也许也JPA可以Hibernate。最终,这是由于我们的(nice!)Logback用法与重载的toString() DAO对象一起使用导致了错误,并被很好地吞下了(但是我偶然发现了它):log.info( "bla bla: {}", obj )产生了bla bla: [FAILED toString()]。对其进行更改以log.info( "bla bla: {}", String.valueOf( obj )使其为null安全,但不能将其吞并,从而使事务打开因不相关的查询而失败。
Andreas Dietrich'9

我遇到了相同类型的错误。我必须在sql之前释放连接。我的代码是connection.commit()
md。ariful ahsan

Answers:


203

我在使用Java和postgresql在表上进行插入时遇到此错误。我将说明如何重现此错误:

org.postgresql.util.PSQLException: ERROR: 
current transaction is aborted, commands ignored until end of transaction block

摘要:

出现此错误的原因是因为您输入了事务,并且其中一个SQL查询失败,并且吞噬了该失败并忽略了它。但这还不够,然后您使用相同的连接,并使用SAME TRANSACTION运行另一个查询。该异常会引发第二个格式正确的查询,因为您正在使用断开的事务来执行其他工作。默认情况下,PostgreSQL会阻止您执行此操作。

我正在使用: PostgreSQL 9.1.6 on x86_64-redhat-linux-gnu, compiled by gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2), 64-bit".

我的PostgreSQL驱动程序是: postgresql-9.2-1000.jdbc4.jar

使用java版本: Java 1.7

这是表create语句,用于说明异常:

CREATE TABLE moobar
(
    myval   INT
);

Java程序导致错误:

public void postgresql_insert()
{
    try  
    {
        connection.setAutoCommit(false);  //start of transaction.

        Statement statement = connection.createStatement();

        System.out.println("start doing statement.execute");

        statement.execute(
                "insert into moobar values(" +
                "'this sql statement fails, and it " +
                "is gobbled up by the catch, okfine'); ");

        //The above line throws an exception because we try to cram
        //A string into an Int.  I Expect this, what happens is we gobble 
        //the Exception and ignore it like nothing is wrong.
        //But remember, we are in a TRANSACTION!  so keep reading.

        System.out.println("statement.execute done");

        statement.close();

    }
    catch (SQLException sqle)
    {
        System.out.println("keep on truckin, keep using " +
                "the last connection because what could go wrong?");
    }

    try{
        Statement statement = connection.createStatement();

        statement.executeQuery("select * from moobar");

        //This SQL is correctly formed, yet it throws the 
        //'transaction is aborted' SQL Exception, why?  Because:
        //A.  you were in a transaction.
        //B.  You ran a sql statement that failed.
        //C.  You didn't do a rollback or commit on the affected connection.

    }
    catch (SQLException sqle)
    {
        sqle.printStackTrace();
    }   

}

上面的代码为我生成了以下输出:

start doing statement.execute

keep on truckin, keep using the last connection because what could go wrong?

org.postgresql.util.PSQLException: 
  ERROR: current transaction is aborted, commands ignored until 
  end of transaction block

解决方法:

您有几种选择:

  1. 最简单的解决方案:不要进行交易。将设置connection.setAutoCommit(false);connection.setAutoCommit(true);。之所以有效,是因为失败的SQL仅作为失败的sql语句被忽略。欢迎您使所有想要的sql语句失败,而postgresql不会阻止您。

  2. 保持在事务中,但是当您检测到第一个sql失败时,请回滚/重新启动或提交/重新启动事务。然后,您可以根据需要继续在该数据库连接上失败许多SQL查询。

  3. 不要捕获并忽略sql语句失败时引发的异常。然后,程序将在格式错误的查询上停止。

  4. 取而代之的是Oracle,当您在事务内的某个连接上的查询失败并继续使用该连接时,Oracle不会引发异常。

在PostgreSQL的决定,这样做事的防御......甲骨文使你的软你做愚蠢的东西中间出租,可俯瞰它。


10
大声笑@选项4 ...我已经在Oracle上做了很多开发工作,最近开始使用Postgres ... Postgres这样做确实很令人讨厌,现在我们必须真正重写我们的大部分程序,正在从Oracle移植到Postgres。为什么没有像第一个这样的选项使它的行为像Oracle一样但没有自动提交
ADTC 2013年

2
经过一些试验后发现,选项2是您最接近Oracle行为的。如果您需要发布多个更新,并且一次失败不应停止后续更新,则只需rollback()在捕获到Connection时调用即可SQLException。[ 无论如何,我意识到这与PostgreSQL强迫用户使所有内容明确的哲学相一致,而Oracle具有隐式照顾很多事情的哲学。]
ADTC

2
选项2包含不可能的分支or commit/restart the transaction。如我所见,没有办法在异常之后提交。当我尝试提交rollback
-PostgreSQL时

1
我可以确认@turbanoff提出的问题。也可以直接用复制psql。(1)开始事务,(2)发出一些有效的语句,(3)发出无效的语句,(4)commit-> psql将回滚而不是提交。
Alphaaa

1
postgresql.org/message-id/op.ur57x9ue33x80h%40insanity.lain.pl 关于此主题的有趣讨论。如果此问题是由违反约束引发的,则PostgreSQL开发人员建议提前检查冲突(在更新/插入之前进行查询),或使用savepoints回滚到更新/插入之前的位置。有关示例代码,请参见stackoverflow.com/a/28640557/14731
吉利

27

检查输出之前导致该声明current transaction is aborted。这通常意味着数据库引发了一个异常,您的代码已忽略该异常,现在期望下一个查询返回一些数据。

因此,您现在认为状态良好的应用程序与数据库之间存在状态不匹配,这需要您回滚并从头开始重新启动事务。

在这种情况下,您应该捕获所有异常和回滚事务。

这是一个类似的问题。


太好了,除了在这种情况下,它是Infinispan,一个第三方库,与Postgres对话,而不是我的代码。
Jimidy

好吧,情况仍然一样-交易必须回滚。也许检查是否正在使用较新版本的库,或者在其错误跟踪器中引起问题。如果您能找到SQL引起问题的确切原因,则可以使用PostgreSQL可扩展性来解决此问题。
vyegorov

您似乎已经证实了我的怀疑-现在,我将看一下Infinispan 5.1.2的源代码。
Jimidy

公平地讲,在TableManipulation类中,有一个尝试运行select count(*)的尝试陷阱。...也许Postgres驱动程序没有抛出预期的异常之一。我将调试器连接到JBoss,以尝试了解更多信息。
Jimidy

该Bug中建议使用有问题的Infinispan代码:issues.jboss.org/browse/… 我已在运行于JBoss 7.1.1实例上的运行器上附加了调试器,而Postgres在正确的地方抛出了异常。也许是JdbcUtil.safeClose()语句没有发挥作用。我将向Infinispan提出。
Jimidy

13

我认为最好的解决方案是使用java.sql.Savepoint。

在执行可能引发SQLException的查询之前,请使用Connection.setSavepoint()方法,如果将引发异常,则仅回滚到该保存点而不回滚所有事务。

示例代码:

Connection conn = null;
Savepoint savepoint = null;
try {
    conn = getConnection();
    savepoint = conn.setSavepoint();
    //execute some query
} catch(SQLException e) {
    if(conn != null && savepoint != null) {
        conn.rollback(savepoint);
    }
} finally {
   if(conn != null) {
      try {
          conn.close();
      } catch(SQLException e) {}

   }
}

我不小心以某种方式拒绝投票,只是注意到了。不是故意的,除非答案被编辑,否则我无法撤消。
cerberos 2015年

保存点方法是实际的解决方案。我也可以在PHP,Doctrine2和Postgres(9.5)的环境中工作。谢谢
helvete


5

在Ruby on Rails PG中,我创建了一个迁移,迁移了我的数据库,但是忘了重启我的开发服务器。我重新启动服务器,它正常工作。


那也是我的情况。认为这应该是愚蠢的,因为我并没有真正尝试做任何复杂的事情。
Tashows

4

发生此错误的原因是,在错误操作导致无法执行当前数据库操作之前还有其他数据库(我使用google翻译将我的中文翻译成英文)



2

您需要回滚。JDBC Postgres驱动程序非常糟糕。但是,如果您想保留事务并仅回滚该错误,则可以使用保存点:

try {
_stmt = connection.createStatement();
_savePoint = connection.setSavepoint("sp01");
_result = _stmt.executeUpdate(sentence) > 0;
} catch (Exception e){
 if (_savePoint!=null){
 connection.rollback(_savePoint);
}
}

在这里阅读更多:

http://www.postgresql.org/docs/8.1/static/sql-savepoint.html


2

我遇到了同样的问题,但后来意识到数据库中存在一个具有相同名称的表。删除后,我能够导入文件。


这是我的问题,对我而言,表跨两个不同的架构。
番茄

0

这是PostgreSQL的非常奇怪的行为,甚至与“强迫用户使所有内容显式的PostgreSQL哲学”不符-因为该异常是被明确捕获和忽略的。因此,即使这种防御也不成立。在这种情况下,Oracle表现得更加用户友好,并且(就我而言)表现得很正确-它留给了开发人员选择。


0

如果卷上的磁盘空间不足,可能会发生这种情况。


我意识到这不是最常见的原因,但是在我被要求进行故障排除的服务器上就是这种情况。因此,我认为这应该被列为潜在原因。
gregb


0

我将JDBI与Postgres一起使用,并遇到了相同的问题,即,在违反先前事务的语句中的某些约束之后,后续语句将失败(但在我等了20-30秒后,问题消失了)。

经过研究后,我发现问题出在我在JDBI中“手动”进行事务处理,即我用BEGIN; ... COMMIT;包围了语句。原来是罪魁祸首!

在JDBI v2中,我可以仅添加@Transaction批注,并且@SqlQuery或@SqlUpdate中的语句将作为事务执行,并且上述问题不再发生!


0

就我而言,由于文件已损坏,我遇到了此错误。在迭代文件记录时,它给了我同样的错误。

可能会在将来对任何人有所帮助。这是发布此答案的唯一原因。


0

我使用带有@Transactional注解的spring ,并且捕获了异常,对于某些异常,我将重试3次。

对于posgresql,当出现异常时,您不能再使用相同的Connection进行提交。您必须先回滚。

就我而言,我使用DatasourceUtils来获取当前连接并connection.rollback()手动致电。然后调用该方法可重试。





-1

将隔离级别从可重复读取更改为已提交读取。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.