多租户应用闲置后租户数据源连接关闭问题求助
解决多租户应用闲置后租户数据源连接关闭问题
你的问题核心是租户数据源的连接池缺少连接存活检测配置,闲置一段时间后数据库主动断开了连接,而主库是通过JNDI获取的,容器(比如Tomcat)默认已经配置了连接池的有效性检测,所以主库连接能保持正常。
问题根源
绝大多数数据库都会主动关闭长时间闲置的连接(比如SQL Server默认连接超时约30分钟),你通过DataSourceBuilder创建的租户数据源,默认没有开启连接池的空闲连接有效性验证和失效连接清理机制。当连接被数据库端断开后,应用层仍持有失效连接,就会抛出The connection is closed异常。
解决方案
在创建租户数据源时,手动添加连接池的存活检测参数,确保连接池定期验证空闲连接状态,自动移除失效连接并创建新连接。以下是修改后的关键代码片段:
// Create TENANT dataSource Map<Object, Object> resolvedDataSources = new HashMap<Object, Object>(); for (String tenantId : groups.keySet()) { Map<String, String> groupKV = groups.get(tenantId); DataSourceBuilder dataSourceBuilder = new DataSourceBuilder(this.getClass().getClassLoader()); dataSourceBuilder.driverClassName(groupKV.get("DATASOURCE_CLASS")) .url(groupKV.get("DB_URL")) .username(groupKV.get("USER_NAME")) .password(groupKV.get("DB_PASSWORD")); // 针对Tomcat JDBC Pool配置连接存活检测(你当前使用的正是该连接池) if (dataSourceBuilder.getType() == org.apache.tomcat.jdbc.pool.DataSource.class) { org.apache.tomcat.jdbc.pool.DataSource tenantDs = (org.apache.tomcat.jdbc.pool.DataSource) dataSourceBuilder.build(); // SQL Server的连接有效性验证语句 tenantDs.setValidationQuery("SELECT 1"); // 空闲时自动验证连接有效性 tenantDs.setTestWhileIdle(true); // 每5分钟执行一次空闲连接检测 tenantDs.setTimeBetweenEvictionRunsMillis(300000); // 连接空闲4分钟后进入检测范围 tenantDs.setMinEvictableIdleTimeMillis(240000); // 每次检测的连接数量 tenantDs.setNumTestsPerEvictionRun(3); resolvedDataSources.put(tenantId, tenantDs); } else { // 若切换为其他连接池(如HikariCP),需替换为对应配置参数 resolvedDataSources.put(tenantId, dataSourceBuilder.build()); } if(LOGGER.isInfoEnabled()) LOGGER.info("Building datasource : "+tenantId); }
额外优化建议
- 统一连接池配置:让租户数据源的连接池参数和主库JNDI的配置保持一致,避免出现差异化问题
- 按需启用借取时验证:如果业务对连接可靠性要求极高,可以设置
testOnBorrow=true,在获取连接时强制验证有效性,但这会带来轻微性能开销,需根据场景权衡 - 添加动态刷新机制:可以定时从主库重新加载租户数据源配置,同时刷新连接池,避免配置变更后需要重启服务
补充:如果后续切换到HikariCP连接池,对应的核心参数为
connectionTestQuery(验证语句)、keepaliveTime(连接存活检测间隔)、validationTimeout(验证超时时间),需对应调整。
内容的提问来源于stack exchange,提问作者Mayank Raghav
相关产品推荐
相关产品推荐

