异步 jdbc 调用是否可行?

2022-08-31 06:48:51

我想知道是否有一种方法可以对数据库进行异步调用?

例如,假设我有一个大请求,需要很长时间来处理,我想发送请求并在请求返回值时收到通知(通过传递监听器/回调或其他方式)。我不想阻止等待数据库应答。

我不认为使用线程池是一种解决方案,因为它无法扩展,在大量并发请求的情况下,这将产生非常大量的线程。

我们在网络服务器上遇到了这种问题,我们已经通过使用select/poll/epoll系统调用找到了解决方案,以避免每个连接有一个线程。我只是想知道如何与数据库请求具有类似的功能?

注意:我知道使用FixedThreadPool可能是一个很好的解决方法,但我感到惊讶的是,没有人开发出一个真正的异步系统(不使用额外的线程)。

** 更新 **
由于缺乏真正实用的解决方案,我决定自己创建一个库(finagle 的一部分):finagle-mysql。它基本上解码/解码mysql请求/响应,并在引擎盖下使用Finagle/Netty。即使有大量的连接,它的扩展性也非常好。


答案 1

我不明白任何将JDBC调用包装在Actor,executors或其他任何东西中的方法都可以在这里有所帮助 - 有人可以澄清吗?

当然,基本问题是JDBC操作阻塞了套接字IO。当它这样做时,它会阻止线程运行 - 故事结束。无论你选择使用哪种包装框架,它最终都会有一个线程保持忙碌/阻塞,每个并发请求。

如果底层数据库驱动程序(MySql?)提供了一种拦截套接字创建的方法(参见SocketFactory),那么我认为可以在JDBC api之上构建一个异步事件驱动的数据库层,但我们必须将整个JDBC封装在事件驱动的外观后面,并且该外观看起来不像JDBC(在它是事件驱动的之后)。数据库处理将在与调用方不同的线程上进行异步处理,并且您必须弄清楚如何构建不依赖于线程相关性的事务管理器。

像我提到的方法一样,即使是单个后台线程也可以处理并发JDBC exec的负载。在实践中,您可能会运行一个线程池来利用多个内核。

(当然,我不是在评论原始问题的逻辑,只是回答了暗示在阻塞套接字IO的场景中,没有选择器模式的用户就可以并发 - 更简单,只需计算出典型的JDBC并发并放入适当大小的连接池中)。


看起来MySql可能会按照我建议---的路线做一些事情 http://code.google.com/p/async-mysql-connector/wiki/UsageExample


答案 2

通过JDBC对数据库进行异步调用是不可能的,但是您可以使用Actor对JDBC进行异步调用(例如,actor通过JDBC调用DB,并在调用结束时向第三方发送消息),或者,如果您喜欢CPS,可以使用管道期货(promises)(一个好的实现是Scalaz Promises)。)

我不认为使用线程池是一种解决方案,因为它无法扩展,在大量并发请求的情况下,这将产生非常大量的线程。

默认情况下,Scala actor是基于事件的(而不是基于线程的) - 继续调度允许在标准JVM设置上创建数百万个Actor。

如果你的目标是Java,Akka Framework是一个Actor模型实现,它对于Java和Scala都有一个很好的API。


除此之外,JDBC的同步特性对我来说非常有意义。数据库会话的成本远远高于 Java 线程被阻塞(在前台或后台)并等待响应的成本。如果您的查询运行时间太长,以至于执行器服务(或包装Actor/fork-join/promise并发框架)的功能对您来说还不够(并且您消耗了太多的线程),那么首先应该考虑数据库负载。通常,来自数据库的响应返回得非常快,并且由固定线程池支持的执行程序服务是一个足够好的解决方案。如果您有太多长时间运行的查询,则应考虑预先(预)处理 - 例如每晚重新计算数据或类似的东西。


推荐