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

org.postgresql.util.PSQLException: ERROR: prepared statement "S_1" already exists

我在网上发现了错误报告,但是它们似乎都适用于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:

事实证明,这是使用 session 池以外的任何东西时发生的pgBouncer问题。我们正在使用事务池,它显然不支持准备好的语句。通过切换到 session 池,我们解决了这个问题。

不幸的是,这对于我们的用例来说不是一个好的解决方案。对于pgBouncer,我们有两种单独的用法:我们系统的一部分进行批量更新,这最有效的方式是准备语句,而另一部分则需要快速连续地进行许多连接。由于pgBouncer不允许在 session 池事务池之间来回切换,因此为了满足我们的需求,我们不得不在不同的端口上运行两个单独的实例。

编辑2:

我碰到this link,张贴者在那贴了自己的补丁。如果事实证明它是安全有效的,那么我们正在考虑将其实现供我们自己使用。

最佳答案

新的更好的答案

要放弃 session 状态并有效地忘记“S_1” 准备好的语句,请在PgBouncer配置中使用server_reset_query选项。

旧答案

参见http://pgbouncer.projects.postgresql.org/doc/faq.html#_how_to_use_prepared_statements_with_transaction_pooling

切换到 session 模式不是理想的解决方案。 Transacion合并效率更高。但是对于事务池,您需要无状态的DB调用。

我认为您有三种选择:

  • 在jdbc驱动程序
  • 中禁用PS
  • 在您的Java代码
  • 中手动取消分配它们
  • 配置pgbouncer使其在事务结束时丢弃它们。

  • 我会尝试选项1或选项3-取决于您的应用使用它们的实际方式。

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

    http://pgbouncer.projects.postgresql.org/doc/config.html(搜索server_reset_query),

    或谷歌为此:
    postgresql jdbc +preparethreshold
    

    关于java - Postgres-错误:已准备好的语句 “S_1”已存在,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7611926/

    10-11 10:54