【问题标题】:How to safely kill a query which has timed out如何安全地终止已超时的查询
【发布时间】:2019-04-04 17:18:32
【问题描述】:

我正在使用 PostgreSQL JDBC,并且我有一些选择和插入查询的连接。有些查询需要一些时间,所以我添加了超时。问题是超时关闭了连接,但是查询仍然在db服务器中执行并创建了锁。

问题的简化代码(真正的代码要复杂得多,大得多,但没关系):

    PGPoolingDataSource source = new PGPoolingDataSource();
    source.setUrl(url);
    source.setUser(user);
    source.setPassword(password);
    source.setMaxConnections(10);
    source.setSocketTimeout(5); // Timeout of 5 seconds

    // Insert a row data, and make timeout
    Connection con = source.getConnection();
    con.setAutoCommit(false);
    try {
        Statement st2 = con.createStatement();
        st2.execute("insert into data.person values (4, 'a')");

        Statement st3 = con.createStatement();
        st3.executeQuery("select pg_sleep(200)"); // A query which takes a lot of time and causes a timeout
        con.commit();
        con.close();
    } catch (SQLException ex) {

        if (!con.isClosed()) {
            con.rollback();
            con.close();
        }
        ex.printStackTrace();
    }


    Connection con2 = source.getConnection();
    con2.setAutoCommit(false);
    try {
        Statement st2 = con2.createStatement();

        // This insert query is locked because the query before is still executed, and the rollback didn't happen yet, and the row with the id of 4 is not released
        st2.execute("insert into data.person values (4, 'b')");
        con2.commit();
        con2.close();
    } catch (SQLException ex) {

        if (!con2.isClosed()) {
            con2.rollback();
            con2.close();
        }
        ex.printStackTrace();
    }

data.person 是一个包含idname 的表。)

超时关闭连接,它甚至没有到达con.rollback(); 行。我读过,当查询发生异常时,它会在后台回滚,所以没关系。

但是查询需要很长时间(几个小时),因此在大选择查询完成后会发生回滚。所以,我无法将行添加到data.person 几个小时(我第二次尝试插入时,我得到一个超时异常,因为它等待释放锁......)。

我读到我可以使用 PostgreSQL 中的函数pg_terminate_backend 来终止查询,这样我可以第二次执行插入查询。

我的问题是:

1) 它有多安全?

2) 这种解决方案有多普遍?

3) 有 JDBC 或 PostgreSQL 提供的更安全的解决方案吗?

【问题讨论】:

  • 你可以设置postgresql服务器的超时时间看看这里dba.stackexchange.com/questions/164419/…,因为你的close函数只会关闭你的java客户端与DB的连接。
  • 感谢@VadymMotsukh,但它不适合我的项目。我只需要在与此 PGoolingDataSource 的连接上超时。对于其他连接,它们可以运行几个小时。
  • 检查答案stackoverflow.com/questions/11291456/…您可以尝试“pg_cancel_backend”进行软停止查询

标签: java postgresql jdbc timeout


【解决方案1】:

pg_terminate_backend 将起作用,如果您想中断查询并关闭数据库连接,这是安全且正确的过程。

还有pg_cancel_backend会中断查询但保持连接打开。

这些函数要求您知道会话后端进程的进程 ID,您可以通过 pg_backend_pid 函数获得。

您必须在与原始数据库连接不同的数据库连接上运行这些语句!

另一种可能更简单的方法是设置statement_timeout。这可以在配置文件中设置,也可以为单个会话或事务设置。要为事务设置它,请使用:

BEGIN;  -- in JDBC, use setAutoCommit(false)
SET LOCAL statement_timeout = 30000;  -- in milliseconds
SELECT /* your query */;
COMMIT;

【讨论】:

  • 谢谢!帮助很大:)
猜你喜欢
  • 2015-09-12
  • 2014-04-02
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多