1 问题现象
由于GaussDB当前没有自已的JDBC连接池,因此GaussDB建议使用第三方的Druid、Hikari CP、dbcp2等连接池。
2 Druid常见参数
将JDBC驱动包和Druid驱动包添加到工程中,配置数据库连接池相关参数:
|------------------------------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 参数 | 默认值 | 说明 |
| url | - | 连接数据库的URL。 |
| username | - | 用户名。 |
| password | - | 密码。 |
| driverClassName | 填写org.postgresql.Driver | 数据库驱动名称。 |
| initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时。 |
| maxActive | 8 | 线程池中最大的连接数。 |
| minIdle | 0 | 线程池最小空闲数。Druid会定期扫描连接数情况,如果扫描的值大于该值就关闭多余的连接数,小于就创建符合要求的连接数;这个参数主要应用于突然有大量请求的时候,创建新的连接数,该操作比较耗时。 |
| connectTimeout | - | 连接数据库超时时间,单位:ms。 |
| socketTimeout | - | socket连接数据库连接超时时间,单位:ms。 |
| maxWait | -1 | 连接池中连接用完时,新的请求等待时间,单位:ms。 -1表示无限等待,直到超时为止。 |
| poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升较大。 |
| maxOpenPreparedStatements | - | 启用PSCache,必须配置大于0。 当大于0时,poolPreparedStatements自动触发修改为true。 |
| validationQuery | SELECT 1 | 用来检测连接是否有效的SQL。 如果validationQuery为空,则testOnBorrow、testOnReturn、testWhileIdle这三个参数都不会起作用,因为这三个参数都是通过执行参数validationQuery指定的SQL来验证数据库连接的有效性。 |
| testOnBorrow | - | 申请连接时执行validationQuery检测连接是否有效,这个配置可能会降低性能,请谨慎操作。 |
| testOnReturn | - | 归还连接时执行validationQuery检测连接是否有效,这个配置可能会降低性能,请谨慎操作。 |
| testWhileIdle | true | 申请连接的时候检测,建议配置为true,不影响性能,并且保证安全性 。如果空闲时间大于timeBetweenEvictionRunMills,执行validationQuery检测连接是否有效都不会起作用。 |
| timeBetweenEvictionRunsMillis | 60s | 执行validationQuery检测连接是否有效。判断连接池的连接空闲数是否大于minIdle,如果是则关闭多余的连接数,少则会补上(如果当前连接池中某个连接在空闲了timeBetweenEvictionRunsMillis时间后仍然没有使用,则会被物理性关闭掉)。 有两个含义: 1. Destroy线程会检测连接的间隔时间。 2. testWhileIdle的判断依据,详细看testWhileIdle属性的说明。 |
| minEvictableIdleTimeMillis | 30min | 连接保持空闲而不被驱逐的最长存活时间。Destroy线程中如果检测到当前连接的最后活跃时间和当前时间的差值大于minEvictableIdleTimeMillis,则关闭当前连接。 说明:这个参数和timeBetweenEvictionRunsMillis参数有点冲突,可默认不配置该参数。 |
| connectionInitSqls | - | 物理连接初始化的时候执行SQL。 |
| exceptionSorter | - | 当数据库抛出一些不可恢复的异常时,抛弃连接。 |
| filters | - | 通过别名的方式配置扩展插件,属性类型是字符串。常用的插件有监控统计用的filter: * stat:监控统计。 * log4j:日志记录。 * wall:防御sql注入。 |
| proxyFilters | - | 类型是List<com.alibaba.druid,filter.Filter>,可同时配置filter和proxyFilters,这两个是组合关系。 |
| removeAbandoned | false | 如果连接泄露,是否需要回收泄露的连接。 在getNumActive()快要到getMaxActive()的时候,系统会进行无效的连接回收,回收的连接为removeAbandonedTimeout(默认300秒)中设置的秒数后没有使用的连接; 对于建立时间超过removeAbandonedTimeout的连接强制关闭。 |
| removeAbandonedTimeout | 300s | 设置Druid强制回收连接的时限,单位:s。当程序从连接池中得到连接开始算起,指定连接建立多长时间druid将强制回收该连接。 |
| logAbandoned | false | 如果回收泄露的连接,是否要打印一条log。 指定发生removeabandoned的时候,是否记录当前线程的堆栈信息到日志中。 |
| removeAbandonedTimeoutMillis | 5min | 连接回收的超时时间。设置"removeAbandoned"为"true",Druid会定期检查线程池溢出的情况,如果不是运行状态,且超过设置的时间就会被回收。 |
| maxEvictableIdleTimeMillis | 7hours | 最大空闲时间,默认为7小时。 |
| maxPoolPrepareStatementPerConnectionSize | 20 | 每个连接最多缓存的SQL数。 |
| keepAlive | false | 初始化连接池时会填充到minIdle的数量。 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis时,则会执行keepAlive操作,打开会一直保持minIdle的数量值。 |
| notFullTimeoutRetryCount | 0 | 连接池内借出的连接加上可用连接小于最大连接数时,则进行重试操作次数,默认为0。 |
| logSlowSql | false | 是否打印慢SQL。 |
3 测试案例
此案例使用select pg_sleep函数产生一个12秒长事务。
package client;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* @version [1.0]
* @Author .wx
* @Date 2024/8/7 19:55
* @description
*/
public class TestDruid {
private static final String username="xxxx";
private static final String passwd="xxxx";
private static final String driver="org.postgresql.Driver";
private static final String sourceURL="jdbc:postgresql://xxx.xx.xx.xx.xxx:17777,xxx.xx.xx.xx.xxx:17777,xxx.xx.xx.xx.xxx:17777/xxxx?" +
"connectTimeout=5&socketTimeout=60";
public static void test(){
DruidPooledConnection connection = null;
try {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(sourceURL);
druidDataSource.setUsername(username);
druidDataSource.setPassword(passwd);
druidDataSource.setDriverClassName(driver);
druidDataSource.setTestWhileIdle(true); //是否空闲检测
druidDataSource.setValidationQuery("select 1");//检测sql
druidDataSource.setValidationQueryTimeout(3000);//检测sql的超时时长
druidDataSource.setTimeBetweenEvictionRunsMillis(34000);//检测间隔时长 ms
druidDataSource.setInitialSize(1);//初始化连接
druidDataSource.setMinIdle(1);//最小连接
druidDataSource.setMaxActive(5);//最大活跃数(连接数)
druidDataSource.setMaxWait(3000);//获取连接的最大等待时间
druidDataSource.setMaxEvictableIdleTimeMillis(60000);//连接在连接池中最长的空闲时间,超过这个时间的连接将被强制回收
druidDataSource.setMinEvictableIdleTimeMillis(30000);//连接在连接池中最短的空闲时间,连接池中的连接空闲时间低于这个时间将不会被回收
druidDataSource.setTestOnBorrow(false);//是否在获取连接时验证连接有效性
druidDataSource.setTestOnReturn(false);//是否在归还连接时验证连接有效性。
//druidDataSource.setSocketTimeout(60000);
//druidDataSource.setConnectTimeout(5000);
//druidDataSource.setKeepAlive(true);//网络层
//druidDataSource.setKeepAliveBetweenTimeMillis(20000);
connection = druidDataSource.getConnection();
//执行业务完成后,关闭此连接后会将连接放入连接池成为空闲连接
connection.close();
Thread.sleep(32000);
//再次取出连接
connection = druidDataSource.getConnection();
System.out.println("socketTimeout时间为:"+connection.getNetworkTimeout());
PreparedStatement preparedStatement = connection.prepareStatement("select pg_sleep(12)");
preparedStatement.executeQuery();//执行sql
System.out.println("sql执行完成");
preparedStatement.close();
connection.close();
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
test();
}
}
4 常见问题处理
1、 socket is closed; Sending Urgent packet failed, detail: Socket Closed. An I/O error occurred while sending to the backend.detail:Read timed out;
a、 连接串配置了socketTimeout,连接池没有配置socketTimeout,业务执行sql时长并没有超过此配置,报此错误,德鲁伊版本1.2.15和1.2.16,这两个版本connectTimeout与socketTimeout都需要设置;1.2.17至1.2.21其他版本此类问题,只需要设置socketTimeout
b、 德鲁伊版本使用了1.21之后,连接串配置了socketTimeout,连接池也配置socketTimeout,业务执行sql时长并没有超过此配置,报此错误
2、 socket is not closed; Urgent packet sent to backend successfully; An I/O error occured while sending to the backend.detail:EOF Exception;
a、 修改连接池配置:调整TimeBetweenEvictionRunsMillis参数检测时长。
b、 修改数据库session_timeout
5 批注
应用在使用jdbc驱动与GaussDB建立业务操作,使用Druid管理连接池的情况下,掌握常见的问题处理。