[PGSQL]PostgreSQL和MySQL中的一些超时参数

当网络临时性中断一会后然后又恢复或中间出现丢包等临时性故障,一般要求应用程序能自动恢复。同样应用程序连接数据库,当应用与数据库之间的网络出现故障后,也需要应用能自动从这个临时性故障中恢复。

在最早的TCP设计中,当没有数据包时,它本身并没有心跳。也就是说当应用向数据库发送一个请求后,数据库一直没有返回结果时,应用程序是不知道是因为网络出现问题导致数据库返回的结果丢失了,还是数据库服务器还一直在执行SQL。虽然后面的TCP协议增加了keepalive的心跳包,但多数操作系统的心跳包的间隔时间要么很长,要不默认没有设置。如Linux下的keepalive的设置是2小时,这对于多数应用都是太长了。所以应用程序通常使用超时的机制来解决这个问题。也就是设置socket的超时时间,即socketTimeout。

在JDBC中,设置超时时间,通常可以在连接数据库中的URL中以参数的形式设置,如在PostgreSQL中:

jdbc:postgresql://127.0.0.1:5432/osdba?socketTimeout=180

在MySQL中:

jdbc:MySQL://127.0.0.1:3306/osdba?socketTimeout=180000

需要注意的是,在PostgreSQL中socketTimeout的单位为秒,而MySQL中的单位为毫秒。

在JDBC中,Statement.setQueryTimeout()来设置查询的超时时间,不同的数据库的JDBC,这个超时时间实现的原理是不一样的。MySQL中,是启动一个timer任务,到了超时时间,查询还没有返回,则直接调用MySQL的kill指令把session终止掉。在PostgreSQL中,到了超时时间,向服务器发送取消执行的命令,所以在PostgreSQL中超时后得到的错误是“ERROR: canceling statement due to user request”。

需要注意的是:

即使设置了查询超时,当网络出错时,查询也可能会出现hang,这必须通过设置socketTimeout来解决

实际对于PostgreSQL来说,可以直接在服务端端参数设置查询的超时时间:

SET statement_timeout=3000;

PostgreSQL JDBC的连接的超时参数为loginTimeout,单位为秒:

jdbc:postgresql://127.0.0.1/osdba?loginTimeout=10    

MySQL JDBC的连接的超时参数为connectTimeout,单位为毫秒:

jdbc:MySQL://127.0.0.1:3306/osdba?connectTimeout=10000

MySQL数据库服务端的一些超时的参数说明:

  • connect_timeout: 在获取连接阶段(authenticate)起作用
  • interactive_timeout:交互连接的模式后,连接的空闲时间超过这个设置值时,连接会被服务器关闭。
  • wait_timeout:非交互连接的模式后,连接的空闲时间超过这个设置值时,连接会被服务器关闭。
  • net_read_timeout:当等待从socket读更多的数据时,数据一直没有过来,等待的超时时间。
  • net_write_timeout:当往socket写数据时被阻塞等待的超时时间。

在PostgreSQL中没有类似MySQL中的“wait_timeout”参数,但可以自己写一个crontab任务查询pg_stat_activity表,发现一个Idle的连接超过一定的时间后,kill掉。

PostreSQL的锁超时参数:

  • lock_timeout

MySQL中的锁超时参数:

  • innodb_lock_wait_timeout

网上的一些数据库超时的文章:

深入理解JDBC的超时设置

Understanding JDBC Internals & Timeout Configuration

Java项目中超时问题解决方案汇总

mysql driver query timeout实现

网上说PostgreSQL的JDBC 9.2-100x的驱动有一个bug,当使用setQueryTimeout后,当执行完后,定时器没有释放,导致虽然连接释放回了连接池,但到了超时时间会把别人的正在执行的SQL取消掉,链接:

Bug report: buggy implementation of setQueryTimeout() in latest JDBC drivers 9.2-100x (AbstractJdbc2Statement.java)

目前我还不确定这个bug是否修复了。