有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

PGBouncer+JDBC中的java connect_查询设置

我正在将PGBouncer配置为我的应用程序的数据库连接池。我还在会话池模式中使用它

由于某些应用程序要求,我需要在使用每个连接期间保留一个临时表。我目前正在使用connect\u query设置创建我的临时表

根据文档,此查询“在建立连接后执行”。据我所知,这意味着每次从池中借用连接时都会执行connect\u查询

我希望避免以下情况:

  1. 我从池中借用了一个连接,如果物理连接需要的话 不存在,将创建它。连接查询将被删除 执行
  2. 我返回到池的连接
  3. 我再次请求到池的连接,让我们假设池重用步骤1)中使用的相同连接并返回它。再次执行连接查询

更新 我可以看到,当通过JDBC连接到PGBouncer并使用该连接执行查询时,每个连接请求都会执行一次connect_查询。以下面的java类为例:

public class TestPgbouncerConnectQuery {

  public static void main(String[] args) {
    for (int i = 0; i < 1000; i++) {
      try {
        System.out.println("Iteration: " + i);
        Connection conn = getConnection();
        executeQuery(conn);
        conn.close();
      } catch (SQLException e) {
      }
    }
  }

  private static Connection getConnection() {
    Connection conn = null;
    try {
      Properties properties = new Properties();
      properties.setProperty("user", "myuser");
      properties.setProperty("password", "mypass");
      Class.forName("org.postgresql.Driver");
      conn = DriverManager.getConnection("jdbc:postgresql://localhost:6432/mydatabase", properties);
      conn.setAutoCommit(false);
    } catch (Exception e) {
    }
    return conn;
  }

  private static void executeQuery(Connection conn) {
    PreparedStatement ps = null;
    try {
      ps = conn.prepareStatement("select 1");
      ps.executeQuery();
    } catch (Exception e) {
    } finally {
      if (ps != null) {
        try {
          ps.close();
        } catch (Exception e) {
        }
      }
    }
  }
}

执行此代码后,如果我查询pg_stat_语句:

select * from pg_stat_statements

我可以看到,connect\u查询在检索每个连接时执行一次。但是如果我对这一行进行注释,为了不在每次迭代中执行查询:

executeQuery(conn);

我无法重现此问题,即在pg_stat_语句中,connect_查询不会在检索到的每个连接中出现一次


共 (1) 个答案

  1. # 1 楼答案

    我认为它能满足你的需要:

    -bash-4.2$ psql -p 6432 -d t -U v -h 1.1.1.1
    Password for user v:
    psql (9.3.18)
    Type "help" for help.
    
    t=> select * from tt;
     i
     -
    (0 rows)
    
    t=> insert into tt select 1;
    INSERT 0 1
    t=> select * from dblink('port=6432 dbname=t hostaddr=1.1.1.1 user=v password=v','select i from tt') as t(i int);
     i
     -
    (0 rows)
    
    t=> select i from tt;
     i
     -
     1
    (1 row)
    
    t=> select * from dblink('port=5432 dbname=mon hostaddr=1.1.1.1 user=v password=v','select i from tt') as t(i int);
    ERROR:  relation "tt" does not exist
    CONTEXT:  Error occurred on dblink connection named "unnamed": could not execute query.
    t=> select current_database();
     current_database
             
     mon
    (1 row)
    

    pgbouncer上的新会话以静默方式创建临时表(不存在例外),并可用于新会话-无需重新创建或检查。会话池模式中的内容对于不同的会话是不同的。如果我连接不超过pgbouncer临时表不存在

    以下是配置:

    t=> \! head -2 /etc/pgbouncer/pgbouncer.ini
    [databases]
    t = host=/var/run/postgresql dbname=mon connect_query = 'create temp table tt(i int)'
    

    更新

    现在我认为它不适合你,因为它创建的表是“物理连接”,而不是从池中获取连接。以下是证据:

    -bash-4.2$ psql -p 6432 -d t -U v -h localhost
    Password for user v:
    psql (9.3.18)
    Type "help" for help.
    
    t=> insert into tt select 5;
    INSERT 0 1
    t=> \q
    -bash-4.2$ psql -c "select query from pg_stat_activity"
                   query
                      
     DISCARD ALL
     select query from pg_stat_activity
    (2 rows)
    
    -bash-4.2$ psql -p 6432 -d t -U v -h localhost
    Password for user v:
    psql (9.3.18)
    Type "help" for help.
    
    t=> insert into tt select 5;
    ERROR:  relation "tt" does not exist
    LINE 1: insert into tt select 5;
                        ^
    

    在从池中提供连接之前,它会DISCARD ALL,从而删除所有临时表。这就是为什么我在上述两个会话中的代码都有自己的表,而最新的示例没有。因为在连接上,关闭的表被删除,会话返回池。所以在下一次连接时,新的连接没有启动,但是旧的连接被重新使用了——而且表还没有出现