【发布时间】:2019-02-13 09:10:08
【问题描述】:
场景:
- 表有一行
id=1 - 使用 JDBC 在行
id=1上启动更新命令,但在它获取之前 已提交,建立 JDBC 连接的 java 程序得到 终止 - 现在另一个 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()简单地杀死那些废弃的后端。无需重启服务器 -
9.6+ 可以设置
idle_in_transaction_session_timeout
标签: postgresql jdbc locking postgresql-9.0