【问题标题】:Correct way of using multiple ConnectionPool(s)使用多个 ConnectionPool(s) 的正确方法
【发布时间】:2018-09-16 11:28:36
【问题描述】:

在我的应用程序中,我必须与多个MySQL DB 一个接一个地进行交互(只读)。对于每个数据库,我需要一定数量的连接。与数据库的交互不会在单程中发生:我查询数据库,花一些时间处理结果,再次查询数据库,再次处理结果等等。

这些交互中的每一个都需要多个连接 [我同时触发多个查询],因此我需要一个ConnectionPool,它会在我开始与数据库交互时生成,并且直到我完成对该数据库的所有查询(包括我不查询时的中间时间间隔,只处理结果)。


我能够成功创建一个具有所需连接数的ConnectionPool,并获得implicit session,如下所示

def createConnectionPool(poolSize: Int): DBSession = {
 implicit val session: AutoSession.type = AutoSession

 ConnectionPool.singleton(
   url = "myUrl",
   user = "myUser",
   password = "***",
   settings = ConnectionPoolSettings(initialSize = poolSize)
 )

 session
}

然后,我在需要与 DB 交互的所有方法中传递此 implicit session。这样,我就可以使用这个session 触发poolSize 没有并发的查询。很公平。

def methodThatCallsAnotherMethod(implicit session: DBSession): Unit = {
  ...
  methodThatInteractsWithDb
  ...
}

def methodThatInteractsWithDb(implicit session: DBSession): Unit = {
  ...
  getResultsParallely(poolSize = 32, fetchSize = 2000000)
  ...
}

def getResultsParallely(poolSize: Int, fetchSize: Int)(implicit session: DBSession): Seq[ResultClass] = {
  import java.util.concurrent.Executors
  import scala.concurrent.ExecutionContext
  import scala.concurrent.duration._

  implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(poolSize))

  val resultsSequenceFuture: Seq[Future[ResultClass]] = {
    (0 until poolSize).map { i =>
      val limit: Long = fetchSize
      val offset: Long = i * fetchSize

      Future(methodThatMakesSingleQuery(limit, offset))
    }
  }
  val resultsFutureSequence: Future[Seq[ResultClass]] = Future.sequence(resultsSequenceFuture)

  Await.result(resultsFuture, 2.minutes)
}

这种技术有两个问题:

  1. 我的应用程序很大并且有很多嵌套的方法调用,因此通过所有这样的方法(见下文)传递implicit session 是不可行的。
  2. 除了上述与不同数据库的逐一交互之外,我还需要在整个应用程序的整个生命周期内与另一个(固定)数据库建立单一连接。此连接将用于每隔几分钟进行一次小型写入操作n(记录我与其他数据库交互的进度)。因此,我需要多个ConnectionPools,每个数据库一个

根据我对ScalikeJdbcdocs 的了解,我想出了以下方法,不需要我到处传递implicit session

def createConnectionPool(poolName: String, poolSize: Int): Unit = {
  ConnectionPool.add(
    name = poolName,
    url = "myUrl",
    user = "myUser",
    password = "***",
    settings = ConnectionPoolSettings(initialSize = poolSize)
  )
}

def methodThatInteractsWithDb(poolName: String): Unit = {
  ...
  (DB(ConnectionPool.get(poolName).borrow())).readOnly { implicit session: DBSession =>
    // interact with DB
    ...
  }
  ...
}

虽然这可行,但我不再能够并行化 db 交互。这种行为很明显,因为我使用的是borrow() 方法,它从 中获取单个连接。这反过来又让我想知道为什么 AutoSession 的事情更早起作用:为什么我能够使用单个 implicit session 同时触发多个查询?如果那件事奏效了,那为什么这不起作用呢?但是我没有找到如何从支持多个连接的ConnectionPool 获取DBSession 的示例。


总而言之,我有 2 个问题和 2 个解决方案:每个问题一个。但我需要一个可以解决这两个问题的单一(通用)解决方案。

ScalikeJdbc 的有限文档没有提供很多帮助,ScalikeJdbc 上的博客/文章几乎不存在。 请提出正确的方法/一些解决方法。


框架版本

  • Scala 2.11.11
  • "org.scalikejdbc" %% "scalikejdbc" % "3.2.0"

【问题讨论】:

  • 这是我在ScalikeJdbcGoogle User Group 中关于此问题的帖子的link

标签: scala jdbc scalikejdbc


【解决方案1】:

感谢@Dennis Hunziker,我能够找出the correct way 释放从ScalikeJdbcConnectionPool 借用的连接。可以这样做:

import scalikejdbc.{ConnectionPool, using}
import java.sql.Connection

using(ConnectionPool.get("poolName").borrow()) { (connection: Connection) =>
    // use connection (only once) here
}
// connection automatically returned to pool

有了这个,现在我可以并行化与池的交互了。


为了解决我管理多个ConnectionPools 和跨多个classes 使用连接的问题,我最终编写了一个ConnectionPoolManager,完整的代码可以在here 中找到。通过卸载任务

  • 创建池
  • 从池中借用连接
  • 删除池

对于我可以在项目中的任何位置使用的singleton 对象,我能够清除很多混乱并消除了跨方法链传递implicit session 的需要。


EDIT-1

虽然我已经 linked 提供了 ConnectionPoolManager 的完整代码,但这里有一个快速提示,告诉你如何去做

ConnectionPoolManager 的以下方法可以让您从ConnectionPools 借用连接

def getDB(dbName: String, poolNameOpt: Option[String] = None): DB = {
  // create a pool for db (only) if it doesn't exist
  addPool(dbName, poolNameOpt)

  val poolName: String = poolNameOpt.getOrElse(dbName)
  DB(ConnectionPool.get(poolName).borrow())
}

此后,在整个代码中,您可以使用上述方法从池中借用连接并进行查询

def makeQuery(dbName: String, poolNameOpt: Option[String]) = {
  ConnectionPoolManager.getDB(dbName, poolNameOpt).localTx { implicit session: DBSession =>
    // perform ScalikeJdbc SQL query here
  }
}

【讨论】:

    猜你喜欢
    • 2018-04-17
    • 2017-04-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    相关资源
    最近更新 更多