在我的应用程序中,我必须逐个与多个MySQL
DB进行交互(只读)。对于每个DB,我需要一定的连接数。在单一伸展中不会发生与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
。通过这种方式,我可以使用此poolSize
同时触发session
没有查询 。很公平。
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)
}
此技术存在两个问题:
implicit session
传递给所有这样的方法(见下文)是不可行的。ConnectionPool
s,每个数据库一个根据我ScalikeJdbc
docs所做的,我提出了以下方式,并不要求我通过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
...
}
...
}
虽然这有效,但我不再能够并行化数据库交互。这种行为很明显,因为我使用borrow()
方法,从池获取单一连接。反过来,这让我想知道为什么AutoSession
事先有效:为什么我能够使用单个implicit session
同时触发多个查询?如果那件事有效,那么为什么这不起作用呢?但我没有找到如何从支持多个连接的DBSession
获取ConnectionPool
的示例。
总而言之,我有2个问题和2个解决方案:每个问题一个。但我需要一个解决这两个问题的单一(通用)解决方案。
ScalikeJdbc
的有限文档并未提供大量帮助,ScalikeJdbc
上的博客/文章几乎不存在。
请建议正确的方法/一些解决方法。
框架版本
Scala 2.11.11
"org.scalikejdbc" %% "scalikejdbc" % "3.2.0"
答案 0 :(得分:1)
由于@Dennis Hunziker,我得以找出the correct way来释放从ScalikeJdbc
的{{1}}借来的连接。可以完成以下操作:
ConnectionPool
有了这个,现在我可以并行化与池的交互了。
为了解决管理多个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
并在多个ConnectionPool
之间使用连接的问题,我最终编写了一个class
,可以找到完整的代码{{3} }。通过卸载
对于一个ConnectionPoolManager
对象,我可以在项目的任何地方使用它,我可以清除很多混乱情况,并消除了跨方法链的singleton
需求传递。
EDIT-1
虽然我已经here了implicit session
的完整代码,但这里有一个快速提示,提示您如何进行操作
以下ConnectionPoolManager
的跟踪方法可让您从ConnectionPoolManager
s借用连接
ConnectionPool
此后,在整个代码中,您可以使用上述方法从池中借用连接并进行查询
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())
}