Библиотека Apache Pool 2 - соединения не закрываются автоматически
У меня есть следующий код в Scala, который использует Apache pool2
библиотека. Объект для пула OlapConnection
(olap4j
класс, похожий на соединение SQL).
Проблема в том, что я не могу заставить пул автоматически закрывать соединения, когда количество объединенных объектов превышает максимальное.
Если я верну объект в пул (с pool.returnObject
) это вызывает passivateObject
, Если я закрою соединение в passivateObject
Я бы закрывал его каждый раз, когда возвращал объект, а это не то, чего я хочу - мне нужно, чтобы кешировались открытые соединения. Если я не закрою соединение в passivateObject
тогда оно никогда не закроется.
Как заставить это работать?
Скала код:
class OlapConnectionUtil (val pool: ObjectPool[OlapConnection]) {
def connect = {
pool.borrowObject
}
def close(olapConnection: OlapConnection) = {
pool.returnObject(olapConnection)
}
}
class OlapConnectionFactory extends BasePooledObjectFactory[OlapConnection] {
override def create = {
val connectionString = "jdbc:mondrian:Jdbc=jdbc:mysql://localhost:3306/foodmart?" +
"user=x&password=x;Catalog=FoodMart.xml;JdbcDrivers=com.mysql.jdbc.Driver"
val connection = DriverManager.getConnection(connectionString)
connection.unwrap(classOf[OlapConnection])
}
override def wrap(olapConnection: OlapConnection) =
new DefaultPooledObject(olapConnection)
override def passivateObject(pooledObject: PooledObject[OlapConnection] ) {
println("passivateObject WAS CALLED")
pooledObject.getObject.close
}
}
class Test {
val olapConnectionFactory = new OlapConnectionFactory
def test = {
val config = new GenericObjectPoolConfig
config.setMaxIdle(5)
config.setMaxTotal(10)
val util = new OlapConnectionUtil(
new GenericObjectPool[OlapConnection](olapConnectionFactory,config))
val olapConnection = util.connect
// do stuff with olapConnection
util.close(olapConnection)
1 ответ
Если вы откроете JavaDocs для PooledObjectFactory
Вы можете видеть это
passivateObject(org.apache.commons.pool2.PooledObject<T>)
вызывается в каждом случае, когда он возвращается в пул.destroyObject(org.apache.commons.pool2.PooledObject<T>)
вызывается в каждом экземпляре, когда он "удаляется" из пула (будь то из-за ответа отvalidateObject(org.apache.commons.pool2.PooledObject<T>)
или по причинам, специфичным для реализации пула.) Нет гарантии, что уничтожаемый экземпляр будет считаться активным, пассивным или в общем непротиворечивом состоянии.
Другими словами, вы должны поместить свою логику распределения ресурсов в destroyObject
, Вот ваш модифицированный тест с подделкой OlapConnection
реализация
import org.apache.commons.pool2._
import org.apache.commons.pool2.impl._
// fake!
case class OlapConnection(val id: Int) {
def close(): Unit = {
println(s"Close was called for $this")
}
}
class OlapConnectionUtil(val pool: ObjectPool[OlapConnection]) {
def connect = {
pool.borrowObject
}
def close(olapConnection: OlapConnection) = {
pool.returnObject(olapConnection)
}
}
class OlapConnectionFactory extends BasePooledObjectFactory[OlapConnection] {
var cnt = 0
override def create = {
cnt += 1
new OlapConnection(cnt)
}
override def wrap(olapConnection: OlapConnection) =
new DefaultPooledObject(olapConnection)
override def passivateObject(pooledObject: PooledObject[OlapConnection]) {
println("-passivateObject was called")
}
override def destroyObject(pooledObject: PooledObject[OlapConnection]): Unit = {
super.destroyObject(pooledObject)
println("--destroyObject was called")
pooledObject.getObject.close
}
}
object Test {
val olapConnectionFactory = new OlapConnectionFactory
def test = {
val config = new GenericObjectPoolConfig
config.setMaxIdle(5)
config.setMaxTotal(10)
val util = new OlapConnectionUtil(new GenericObjectPool[OlapConnection](olapConnectionFactory, config))
val initConnections = (1 to 10).map(i => util.connect).toList
val closeCons = initConnections
Thread.sleep(100)
println("Start closing")
closeCons.zipWithIndex.foreach(ci => {
Thread.sleep(100)
println(s"Before close ${ci._2 + 1}")
util.close(ci._1)
println(s"After close ${ci._2 + 1}")
})
}
}
Выходные данные этого кода:
До закрытия 1
-passivateObject был вызван
После закрытия 1
До закрытия 2
-passivateObject был вызван
После закрытия 2
До закрытия 3
-passivateObject был вызван
После закрытия 3
До закрытия 4
-passivateObject был вызван
После закрытия 4
До закрытия 5
-passivateObject был вызван
После закрытия 5
До закрытия 6
-passivateObject был вызван
--destroyObject был вызван
Close был вызван для OlapConnection(6)
После закрытия 6
До закрытия 7
-passivateObject был вызван
--destroyObject был вызван
Close был вызван для OlapConnection(7)
После закрытия 7
До закрытия 8
-passivateObject был вызван
--destroyObject был вызван
Close был вызван для OlapConnection(8)
После закрытия 8
До закрытия 9
-passivateObject был вызван
--destroyObject был вызван
Close был вызван для OlapConnection(9)
После закрытия 9
До закрытия 10
-passivateObject был вызван
--destroyObject был вызван
Close был вызван для OlapConnection(10)
После закрытия 10
Как вы можете видеть в этом выводе close
вызывается с OlapConnection(6)
как и следовало ожидать, учитывая конфигурацию пула.