当通过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:
当使用除会话池以外的任何内容时,会出现pgBouncer问题。我们使用事务池,显然不支持预准备语句。通过切换到会话池,我们解决了这个问题。
不幸的是,这不是我们用例的好方法。我们对pgBouncer有两个单独的用途:我们系统的一部分进行批量更新,这些更新作为预处理语句最有效,另一部分需要非常快速连续的许多连接。由于pgBouncer不允许在会话池和事务池之间来回切换,因此我们不得不在不同端口上运行两个单独的实例,以满足我们的需求。 / p>
编辑2:
我跑过this link,海报上贴了他自己的贴片。如果它被证明是安全有效的,我们目前正在考虑将它用于我们自己的用途。
答案 0 :(得分:1)
要放弃会话状态并有效忘记“S_1”预设语句,请在PgBouncer配置中使用server_reset_query选项。
切换到会话模式不是理想的解决方案。 Transacion池效率更高。但是对于事务池,您需要无状态数据库调用。
我认为你有三种选择:
我会尝试选项1或选项3 - 具体取决于您的应用使用它们的实际方式。
有关详细信息,请阅读文档:
http://pgbouncer.projects.postgresql.org/doc/config.html(搜索server_reset_query),
或google:
postgresql jdbc +preparethreshold
答案 1 :(得分:0)
当使用除会话池以外的任何内容时,会出现pgBouncer问题。我们使用事务池,显然不支持预准备语句。通过切换到会话池,我们解决了这个问题。
不幸的是,这不是我们用例的好方法。我们对pgBouncer有两个单独的用途:我们系统的一部分进行批量更新,这些更新作为预处理语句最有效,另一部分需要非常快速连续的许多连接。由于pgBouncer不允许在会话池和事务池之间来回切换,因此我们不得不在不同端口上运行两个单独的实例以支持我们的需求,或实施this patch。初步测试表明它运作良好,但时间会证明它是否安全有效。
答案 2 :(得分:0)
在JDBC中禁用准备好的语句。 针对JDBC的正确方法是添加“ prepareThreshold = 0”参数来连接字符串。
jdbc:postgresql://ip:port/db_name?useAffectedRows=true&prepareThreshold=0
答案 3 :(得分:0)
我遇到了这个问题,我们在事务级别配置了pgbouncer,我们使用的是psql 11.8,我们刚刚将psql jar升级到了最新版本,它已经修复。