【问题标题】:postgresql9.0 locked and unresponsive if update operation performed on the row where update operation is interruptedpostgresql9.0 如果在更新操作中断的行上执行更新操作,则被锁定且无响应
【发布时间】:2019-02-13 09:10:08
【问题描述】:

场景:

  1. 表有一行id=1
  2. 使用 JDBC 在行 id=1 上启动更新命令,但在它获取之前 已提交,建立 JDBC 连接的 java 程序得到 终止
  3. 现在另一个 JDBC 连接尝试更新同一行 id=1

观察:

监控数据库时,锁很明显,在同一行上进一步更新操作,导致数据库服务器冻结,必须重新启动才能正常操作...
如果更新查询和会话数减少,锁会在一分钟内释放......但在现实世界的应用程序中,更新会频繁执行并且服务器会冻结

所以我的问题是:

有没有办法(配置、工具、...)为来自客户端的任何死数据库连接强制、关闭和删除 Postgres 服务器中的锁

代码:

package postgrestest;

import java.sql.*;

public class IncompleteTransvanilla implements Runnable {
    private int seq = 0;
    private Connection connection = null;
    private boolean insertoperation = true;

    public static void main(String[] args) throws Exception{
        boolean flag = true;
        if(args.length>0) {flag = false;}
        for(int i=0;i<10;i++) {
            new Thread(new IncompleteTransvanilla(i,flag)).start();
            //Thread.sleep(1000*(int)(Math.random()*10));
        }
        Thread.sleep(10000);
    }

    public IncompleteTransvanilla(int i, boolean flag) {
        try {
            connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/testdb", "postgres", "postgres");
            connection.setAutoCommit(false);
        } catch (Exception e) {
            System.out.println("error");
        }
        seq=i;
        insertoperation = flag;
    }

    public void run() {
        try {
            PreparedStatement statement;
            if(insertoperation == true) {
                System.out.println("Inserting");
                statement = connection.prepareStatement("Insert into uacc(user_id,username,password,email) values(DEFAULT,?,'samplepass','samplemail')");
            }
            else {
                System.out.println("Updating");
                statement = connection.prepareStatement("update uacc set username=? where user_id=1");
            }
            int maxval = 100;
            for(int i=0;i<maxval;i++) {
                statement.setString(1, "sampleuser"+((seq*maxval)+i));
                statement.execute();
            }
            Thread.sleep(10000);
            connection.commit();
        } catch (Exception e) {
            System.out.println("Connection failure.");
        }
    }

}

数据库监控仪表盘截图供参考:

编辑: 服务器中的任何建议/配置可用于自动删除此类锁或配置以减少它等待连接并删除锁的时间?

或者...将 postgres9.0 升级到 9.5 会解决这些问题吗?

【问题讨论】:

  • 显然服务器没有注意到客户端已断开连接。可能是 TCP 配置的问题,通常如果客户端终止,客户端启动的事务将回滚。来自“已终止”Java 程序的连接是否仍显示在 pg_stat_activity 中?如果是,您可以简单地手动杀死它。
  • Postgres 9.0 是 no longer supported 你现在真的应该计划升级了。
  • 您的示例代码根本不会“终止” Java 程序,所以是的,在该连接关闭之前,该程序持有的锁不会被释放。
  • 您可以尝试将tcpKeepAlive=true 添加到 JDBC URL 中,也可以使用服务器的keepalive settings。作为最后的手段,您可以使用pg_terminate_backend() 简单地杀死那些废弃的后端。无需重启服务器

标签: postgresql jdbc locking postgresql-9.0


【解决方案1】:

为了防止客户端在工作中突然死机,您可以使用以下 PostgreSQL 参数:

  • tcp_keepalives_idle:将其设置为 60 之类的低值,以便服务器在一分钟不活动后探测客户端,并在客户端死机时终止会话。

  • idle_in_transaction_session_timeout:将此设置为甚至更低的值,因为没有事务应该长时间保持空闲状态。这将杀死持有锁时空闲的会话。请注意不要破坏数据库上的正常活动!

从 9.0 升级应该是您的首要任务,因为 9.0 已经过时且不受支持,非常危险。不过更新到 v11 而不是 9.5。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多