Scala Future中包装的JDBC调用

Mas*_*ano 5 concurrency scala jdbc

我正在编写一个Akka HTTP Web API,该API使用OJDCB连接到Oracle数据库实例。

据我所知,没有异步JDBC API可以连接到数据库,也没有回调实现,因此,必须阻塞进程线程才能完成调用。

我的问题是:让Akka HTTP自然地允许使用Scala Future处理请求,将数据库调用简单地包装到Scala Future中是一个好主意吗?在等待数据库响应时基础线程是否空闲?

Krz*_*sik 5

底层线程在等待数据库响应时是否空闲? 是的,线程被阻塞,直到 JDBC 调用完成。这不是一件好事,但在adba准备好之前,可能没有更好的选择。

使用Future阻塞 IO(JDBC调用)是一种常见的模式。不过有一些事情需要考虑。github上有一篇关于该主题的精彩文章。

总结文章中描述的一些要点:

  • 将您的阻塞调用包装在blocking块内,如下所示:

    def fetchUser(id: Long): Future[User]  = Future {
       blocking { //mark this operation as blocking
          ...
          preparedStatement.execute()
          ...
       }
    } 
    
    Run Code Online (Sandbox Code Playgroud)
  • 你不应该scala.concurrent.ExecutionContext.Implicits.global用于做任何阻塞的期货,因为你可能会饿死线程池。您应该为阻塞操作创建一个单独的线程池:

    object BlockingIOExecutionContext {
        implicit val ec: ExecutionContextExecutor = ExecutionContext.fromExecutor(
           Executors.newCachedThreadPool()
        ) // create seperate thread pool for our blocking operations
    }
    
    Run Code Online (Sandbox Code Playgroud)

对你来说最好的办法是只使用某种成熟的Scala框架,为你做这些事情,像光滑doobie

  • 我认为在 `Future` 中使用 `blocking` 可以防止线程池饿死,因为它会导致底层执行程序产生更多线程。参见 https://docs.scala-lang.org/overviews/core/futures.html:“只有当每个阻塞调用都包含在一个阻塞调用中时,并发阻塞计算的数量才能超过并行级别......否则,有是线程池......饿死的风险” (2认同)