Postgres - ERROR: prepared statement “S_1” already exists

不想你离开。 提交于 2020-02-26 07:54:29

问题


When executing batch queries via JDBC to pgbouncer, I get the following error:

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

I've found bug reports around the web, but they all seem to deal with Postgres 8.3 or below, whereas we're working with Postgres 9.

Here's the code that triggers the error:

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();
    }
});

Anyone seen this before?

Edit 1:

This turned out to be a pgBouncer issue that occurs when using anything other than session pooling. We were using transaction pooling, which apparently can't support prepared statements. By switching to session pooling, we got around the issue.

Unfortunately, this isn't a good fix for our use case. We have two separate uses for pgBouncer: one part of our system does bulk updates which are most efficient as prepared statements, and another part needs many connections in very rapid succession. Since pgBouncer doesn't allow switching back and forth between session pooling and transaction pooling, we're forced to run two separate instances on different ports just to support our needs.

Edit 2:

I ran across this link, where the poster has rolled a patch of his own. We're currently looking at implementing it for our own uses if it proves to be safe and effective.


回答1:


New, Better Answer

To discard session state and effectively forget the "S_1" prepared statement, use server_reset_query option in PgBouncer config.

Old Answer

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

Switching into session mode is not an ideal solution. Transacion pooling is much more efficient. But for transaction pooling you need stateless DB calls.

I think you have three options:

  1. Disable PS in jdbc driver,
  2. manually deallocate them in your Java code,
  3. configure pgbouncer to discard them on transaction end.

I would try option 1 or option 3 - depending on actual way in which your app uses them.

For more info, read the docs:

http://pgbouncer.projects.postgresql.org/doc/config.html (search for server_reset_query),

or google for this:

postgresql jdbc +preparethreshold



回答2:


Disabling prepared statements in JDBC. The proper way to do it for JDBC is adding "prepareThreshold=0" parameter to connect string.

jdbc:postgresql://ip:port/db_name?useAffectedRows=true&prepareThreshold=0



回答3:


This turned out to be a pgBouncer issue that occurs when using anything other than session pooling. We were using transaction pooling, which apparently can't support prepared statements. By switching to session pooling, we got around the issue.

Unfortunately, this isn't a good fix for our use case. We have two separate uses for pgBouncer: one part of our system does bulk updates which are most efficient as prepared statements, and another part needs many connections in very rapid succession. Since pgBouncer doesn't allow switching back and forth between session pooling and transaction pooling, we're forced to either run two separate instances on different ports just to support our needs, or to implement this patch. Preliminary testing shows it to work well, but time will tell if it proves to be safe and effective.



来源:https://stackoverflow.com/questions/7611926/postgres-error-prepared-statement-s-1-already-exists

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!