Apache Pool2库:连接数超上限时无法自动关闭问题咨询
解决Apache Pool2池化OlapConnection时无法自动清理多余连接的问题
嘿,我刚好之前也用Pool2处理过类似的数据库连接池化问题,你的核心问题是没搞清楚Pool2里各个回调方法的职责,还有池的自动清理逻辑~
先给你理清楚关键:Apache Pool2不会在总连接数超过maxTotal时立刻销毁多余连接,而是当空闲连接数超过maxIdle,或者连接空闲超时的时候,才会自动触发销毁操作。你之前在passivateObject里关闭连接完全搞错了这个方法的用途——它是用来做对象的“钝化”(比如重置连接状态),不是用来销毁对象的。
下面是具体的解决方案,用Scala实现:
1. 先把连接池的配置搞对
首先要调整GenericObjectPool的参数,让它知道什么时候该去清理多余的空闲连接:
import org.apache.commons.pool2.impl.GenericObjectPoolConfig val poolConfig = new GenericObjectPoolConfig[OlapConnection]() { setMaxTotal(20) // 池允许的最大总连接数 setMaxIdle(10) // 最多保留10个空闲连接,超过的会被销毁 setMinIdle(5) // 最少维持5个空闲连接,避免频繁创建销毁 setTimeBetweenEvictionRunsMillis(60000) // 每60秒跑一次空闲连接清理任务 setMinEvictableIdleTimeMillis(180000) // 空闲超过3分钟的连接直接销毁 setTestWhileIdle(true) // 清理时顺便检查连接是否还能用 }
这里的maxIdle一定要小于maxTotal,不然池不会去销毁多余的空闲连接。另外timeBetweenEvictionRunsMillis是开启自动清理的关键,没设置的话池不会主动去检查。
2. 实现正确的PooledObjectFactory
重点是把关闭连接的逻辑放到destroyObject里,passivateObject只做状态重置:
import org.apache.commons.pool2.BasePooledObjectFactory import org.apache.commons.pool2.PooledObject import org.apache.commons.pool2.impl.DefaultPooledObject import org.olap4j.OlapConnection import java.sql.DriverManager class OlapConnectionFactory extends BasePooledObjectFactory[OlapConnection] { // 创建新的OlapConnection override def create(): OlapConnection = { val url = "jdbc:mondrian://localhost/olap" // 换成你的实际连接地址 val user = "your_username" val password = "your_password" DriverManager.getConnection(url, user, password).asInstanceOf[OlapConnection] } // 把连接包装成Pool2需要的PooledObject override def wrap(obj: OlapConnection): PooledObject[OlapConnection] = { new DefaultPooledObject(obj) } // 钝化操作:归还连接时重置状态(比如关闭未关闭的查询、清空会话) override def passivateObject(p: PooledObject[OlapConnection]): Unit = { val conn = p.getObject // 这里做你需要的状态重置,比如关闭打开的Statement Option(conn.createStatement()).foreach(_.close()) // 如果有会话级别的状态,也可以在这里清空 } // 销毁操作:真正关闭连接,池会在需要的时候自动调用这个方法 override def destroyObject(p: PooledObject[OlapConnection]): Unit = { val conn = p.getObject if (!conn.isClosed) { conn.close() } } // 验证连接是否有效,避免返回失效的连接 override def validateObject(p: PooledObject[OlapConnection]): Boolean = { val conn = p.getObject !conn.isClosed && conn.isValid(5) // 5秒超时验证连接可用性 } }
3. 初始化并使用连接池
import org.apache.commons.pool2.impl.GenericObjectPool // 初始化池 val connectionPool = new GenericObjectPool[OlapConnection](new OlapConnectionFactory(), poolConfig) // 借用连接 val conn = connectionPool.borrowObject() // 这里执行你的Olap操作... // 归还连接:此时只会调用passivateObject重置状态,不会关闭连接 connectionPool.returnObject(conn)
为啥之前的方式不对?
passivateObject是每次归还对象都会触发的,你在这里关闭连接的话,等于每次用完就直接销毁了,池根本没法复用连接,完全失去了池化的意义。- 池的自动清理是由内置的空闲对象驱逐器来做的,只有当空闲连接数超过
maxIdle,或者连接空闲时间超过minEvictableIdleTimeMillis时,池才会调用destroyObject去关闭多余或失效的连接。
这样配置之后,当你借用的连接数达到maxTotal,归还后如果空闲数超过maxIdle,池会在下次清理任务运行时自动关闭多余的空闲连接,完全符合你的需求~
内容的提问来源于stack exchange,提问作者ps0604
相关产品推荐
相关产品推荐

