Библиотека 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 Вы можете видеть это

  1. passivateObject(org.apache.commons.pool2.PooledObject<T>) вызывается в каждом случае, когда он возвращается в пул.
  2. 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) как и следовало ожидать, учитывая конфигурацию пула.

Другие вопросы по тегам