Java Postgres-错误:准备好的声明;S_1";已经存在

Java Postgres-错误:准备好的声明;S_1";已经存在,java,postgresql,jdbc,pgbouncer,Java,Postgresql,Jdbc,Pgbouncer,通过JDBC对pgbouncer执行批处理查询时,出现以下错误: org.postgresql.util.PSQLException: ERROR: prepared statement "S_1" already exists 我在网上找到了一些bug报告,但它们似乎都是针对Postgres 8.3或更低版本的,而我们现在使用的是Postgres 9 以下是触发错误的代码: this.getJdbcTemplate().update("delete from xx where usernam

通过JDBC对pgbouncer执行批处理查询时,出现以下错误:

org.postgresql.util.PSQLException: ERROR: prepared statement "S_1" already exists
我在网上找到了一些bug报告,但它们似乎都是针对Postgres 8.3或更低版本的,而我们现在使用的是Postgres 9

以下是触发错误的代码:

this.getJdbcTemplate().update("delete from xx where username = ?", username);

this.getJdbcTemplate().batchUpdate( "INSERT INTO xx(a, b, c, d, e) " + 
                "VALUES (?, ?, ?, ?, ?)", new BatchPreparedStatementSetter() {
    @Override
    public void setValues(PreparedStatement ps, int i) throws SQLException {
        ps.setString(1, value1);
        ps.setString(2, value2);
        ps.setString(3, value3);
        ps.setString(4, value4);
        ps.setBoolean(5, value5);
    }
    @Override
    public int getBatchSize() {
        return something();
    }
});
有人见过这个吗

编辑1:


这是一个pgBouncer问题,在使用除会话池以外的任何方法时都会发生。我们使用的是事务池,它显然不能支持准备好的语句。通过切换到会话池,我们绕过了这个问题

不幸的是,对于我们的用例来说,这不是一个很好的修复方法。pgBouncer有两种不同的用途:我们系统的一部分进行批量更新,这在准备语句时是最有效的,另一部分需要快速连续的许多连接。由于pgBouncer不允许在会话池事务池之间来回切换,我们不得不在不同的端口上运行两个单独的实例,以满足我们的需要

编辑2:


我跑了过去,海报上贴着他自己的补丁。如果它被证明是安全有效的,我们目前正在考虑将其用于我们自己的用途。

这被证明是一个pgBouncer问题,在使用除会话池以外的任何东西时都会发生。我们使用的是事务池,它显然不能支持准备好的语句。通过切换到会话池,我们绕过了这个问题

不幸的是,对于我们的用例来说,这不是一个很好的修复方法。pgBouncer有两种不同的用途:我们系统的一部分进行批量更新,这在准备语句时是最有效的,另一部分需要快速连续的许多连接。由于pgBouncer不允许在会话池事务池之间来回切换,我们被迫在不同的端口上运行两个单独的实例,以支持我们的需要,或者实现。初步测试表明它运行良好,但时间会证明它是否安全有效。

新的、更好的答案 要放弃会话状态并有效地忘记“S_1”准备好的语句,请使用PgBouncer config中的server_reset_查询选项

旧答案 看

切换到会话模式不是理想的解决方案。交易池的效率要高得多。但是对于事务池,您需要无状态DB调用

我认为你有三个选择:

  • 在jdbc驱动程序中禁用PS
  • 在Java代码中手动取消分配它们
  • 配置pgbouncer以在事务结束时丢弃它们
  • 我会尝试选项1或选项3——取决于应用程序使用它们的实际方式

    有关更多信息,请阅读文档:

    (搜索服务器重置查询)

    或谷歌:

    postgresql jdbc +preparethreshold
    

    禁用JDBC中的准备语句。 对于JDBC,正确的方法是添加“prepareThreshold=0”参数来连接字符串

    jdbc:postgresql://ip:port/db_name?prepareThreshold=0
    

    我遇到了这个问题,我们在事务级别配置了pgbouncer,我们使用的是psql 11.8,我们刚刚将psql jar升级到最新版本,它得到了修复。

    可能是pgbouncer的问题?还是过时的JDBC驱动程序?这肯定是pgbouncer的问题。我们绕过了pgbouncer,直接点击了Postgres,准备好的语句就行了。JDBC驱动程序是最新的。是否有一些设置告诉pgbouncer在释放回池时重置连接?听起来你在重复使用以前已经运行过prepare的connetions。@ScottMarlowe有。这是连接池选项。我们使用
    事务池
    ,它应该在事务结束后立即释放回池的连接。这不是释放连接,而是重置连接。如果它没有在连接上重置,那么像准备好的查询这样的旧东西仍然可以存在。“当使用事务池时,服务器重置查询应该是空的,因为客户端不应该使用任何会话功能。”看起来选项3是不可能的。选项1对我们的使用不可行。选项2可能会起作用,但如何实现呢?看来,
    会话\u生命周期
    可能是导致问题的设置。我们现在正在试验它。我很快会回来报告。@Chris:选项3是可能的-pgbouncer医生说一般应该做什么,但在你的情况下,我会试试。关于选项2,请参阅,关于选项1-为什么不?服务器重置查询文档的新链接:请发布用户询问的特定版本的psql的答案,因为升级psql可能会导致其他问题,用户很难理解。并尝试更正/即兴修改问题中发布的代码谢谢您的反馈Dilip D我已经从postgres 8.4升级到postgres.jdbc.4.2-42..2.14,这对我来说很有用-但是也许最好从你的答案中删除useAffectedRows=true?没必要吗?好的,刚把它拆了。不幸的是,链接死了。这是一个存档快照: