postgresql Postgres -错误:已准备好的语句“S_1”已存在

zengzsys  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(6)|浏览(230)

当通过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在使用session pooling以外的任何东西时都会出现的问题。我们使用的是transaction pooling,它显然不支持prepared statements。通过切换到session pooling,我们解决了这个问题。
不幸的是,这对我们的用例来说不是一个好的修复。我们有两个单独的pgBouncer用途:我们的系统的一部分进行批量更新,这是最有效的准备语句,另一部分需要非常快速的连续连接。由于pgBouncer不允许在会话池事务池之间来回切换,我们被迫在不同的端口上运行两个单独的示例,以支持我们的需求。

  • 编辑二:*

我偶然发现了this link,发帖者也推出了自己的补丁,如果它被证明是安全有效的,我们目前正在考虑将其实现为我们自己使用。

nlejzf6q

nlejzf6q1#

在JDBC中禁用预处理语句。对于JDBC来说,正确的方法是在连接字符串中添加“Threshold =0”参数。

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

字符串

mec1mxoz

mec1mxoz2#

这是pgBouncer在使用session pooling以外的任何东西时都会出现的问题。我们使用的是transaction pooling,它显然不支持prepared statements。通过切换到session pooling,我们解决了这个问题。
不幸的是,这对我们的用例来说不是一个好的修复。我们有两个单独的pgBouncer用途:我们的系统的一部分进行批量更新,这是最有效的准备语句,另一部分需要非常快速的连续连接。由于pgBouncer不允许在会话池事务池之间来回切换,我们不得不在不同的端口上运行两个独立的示例来支持我们的需求,或者实现this patch。初步测试显示它工作得很好,但时间会证明它是否安全有效。

mrzz3bfm

mrzz3bfm3#

新的,更好的答案

要放弃会话状态并有效地忘记**“S_1”**prepared语句,请使用PgBouncer配置中的server_reset_query选项。

旧答案

请访问http://pgbouncer.projects.postgresql.org/doc/faq.html#_how_to_use_prepared_statements_with_transaction_pooling
切换到会话模式并不是一个理想的解决方案。事务池要有效得多。但是对于事务池,您需要无状态的DB调用。
我觉得你有三个选择:
1.在jdbc驱动程序中禁用PS,
1.在Java代码中手动释放它们,
1.配置pgbouncer在事务结束时丢弃它们。
我会尝试选项1或选项3 -取决于您的应用程序使用它们的实际方式。
有关更多信息,请阅读文档:
http://pgbouncer.projects.postgresql.org/doc/config.html(搜索server_reset_query),
Google为此:

postgresql jdbc +preparethreshold

字符串

velaa5lx

velaa5lx4#

在我们的案例中,这个问题与pgbouncer无关。由于我们无法将prepareThreshold=0附加到URL,因此我们做了以下修复
查看准备好的声明

select * from pg_prepared_statements;

字符串
取消分配故障表

select * from pg_prepared_statements;
deallocate "S_1";

yfjy0ee7

yfjy0ee75#

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

ssgvzors

ssgvzors6#

从PgBouncer 1.21.0开始,它现在支持协议级别的命名准备语句,这是JDBC使用的。您可以通过将max_prepared_statements设置为非零值来启用此支持。有关详细信息,请查看文档:https://www.pgbouncer.org/config.html#max_prepared_statements

相关问题