是否可以进行异步 jdbc 调用?

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

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

我不认为使用线程池是一种解决方案,因为它不能伸缩,在大量并发请求的情况下,这将产生大量的线程。

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

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

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

88174 次浏览

JDBC 中没有直接的支持,但是您可以选择多个选项,比如 MDB、 Java5中的 Execators。

“我不认为使用线程池是一种解决方案,因为它不能伸缩,在大量并发请求的情况下,这将产生大量的线程。”

我很好奇,为什么有界线程池不能伸缩呢?它是一个池,不是每个请求一个线程,而是每个请求一个线程。我已经使用了相当一段时间,在一个沉重的负载网络应用程序,我们还没有看到任何问题,迄今为止。

我只是在想办法。为什么不能有一个数据库连接池,每个连接池都有一个线程。每个线程都可以访问一个队列。当您希望执行一个需要很长时间的查询时,可以将其放在队列中,然后其中一个线程将拾取并处理它。您永远不会有太多的线程,因为线程的数量是有界的。

编辑: 或者更好,只是一些线程。当一个线程看到队列中的某个内容时,它会从池中请求一个连接并处理它。

也许您可以使用 JMS 异步消息传递系统,它的扩展性非常好,恕我直言:

  • 将消息发送到一个 Queue,订阅者将在其中接受该消息,并运行 SQL 进程。您的主进程将继续运行并接受或发送新请求。

  • 当 SQL 进程结束时,您可以以相反的方式运行: 将一条消息发送到一个 ResponseQueue,其中包含该进程的结果,客户端的侦听器接受该消息并执行回调代码。

通过 JDBC 进行异步调用 数据库是不可能的,但是你可以通过 演员进行异步调用 到 JDBC(例如,Actor 通过 JDBC 对 DB 进行调用,并在调用结束时向第三方发送消息) ,或者,如果你喜欢 CPS,通过 管道期货(承诺)进行异步调用(一个很好的实现是 斯卡拉兹 我保证)

我不认为使用线程池是一种解决方案,因为它不能伸缩,在大量并发请求的情况下,这将产生大量的线程。

Scala 角色默认是基于事件的(不是基于线程的)-延续调度允许在标准 JVM 设置上创建数百万个角色。

如果你的目标是 Java,阿卡框架是一个 Actor 模型实现,它对 Java 和 Scala 都有很好的 API。


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

Java 5.0执行程序可能会派上用场。

可以有固定数量的线程来处理长时间运行的操作。你可以使用 Callable来代替 Runnable,它会返回一个结果。结果被封装在一个 Future<ReturnType>对象中,所以您可以在返回时获得它。

只是一个疯狂的想法: 您可以使用一个包装在某个未来/承诺中的 Iteratee 模式来覆盖 JBDC result 集

哈默史密斯就是这么做的。

我不明白在 Actors、执行器或其他任何东西中包装 JDBC 调用的任何提议方法在这里有什么帮助——有人能澄清一下吗。

当然,最基本的问题是 JDBC 操作阻塞了套接字 IO。当它这样做,它阻止线程其运行的故事结束。无论您选择使用哪种包装框架,每个并发请求都会导致一个线程处于忙碌/阻塞状态。

如果底层数据库驱动程序(MySql?)提供了一种拦截套接字创建的方法(参见 SocketFactory) ,那么我想在 JDBC API 之上构建一个异步事件驱动的数据库层是可能的,但是我们必须将整个 JDBC 封装在一个事件驱动的 facade 之后,这个 facade 看起来不会像 JDBC (在它是事件驱动的之后)。数据库处理将在调用方的另一个线程上异步进行,您必须解决如何构建不依赖于线程关联的事务管理器的问题。

类似我提到的方法甚至允许单个后台线程处理并发 JDBC exec 的负载。实际上,您可能会运行一个线程池来使用多个核。

(当然,我不是在评论最初问题的逻辑,而只是在回答这样的问题: 在没有选择器模式的用户的情况下,在阻塞套接字 IO 的场景中,并发是可能的——只要计算出典型的 JDBC 并发并放入适当大小的连接池就更简单了)。


看起来 MySql 可能会做一些类似于我建议的事情——- Http://code.google.com/p/async-mysql-connector/wiki/usageexample

Commons-dbutils 库支持向其提供 ExecutorService并返回 FutureAsyncQueryRunner。值得检查,因为它很容易使用,并确保您不会泄漏资源。

Ajdbc 项目似乎解决了这个问题 http://code.google.com/p/adbcj/

目前,mysql 和 postgreql 有两个实验性的本地异步驱动程序。

这是个老问题了,但还有更多信息。JDBC 不可能向数据库本身发出异步请求,除非供应商提供 JDBC 的扩展和处理 JDBC 的包装器。也就是说,可以用处理队列封装 JDBC 本身,并实现可以在一个或多个单独的连接上处理队列的逻辑。对于某些类型的调用,这样做的一个优点是,如果负载足够大,逻辑可以将调用转换为 JDBC 批处理,这可以大大加快逻辑速度。这对于插入数据的调用非常有用,只有在出现错误时才需要记录实际结果。一个很好的例子是,如果正在执行插入以记录用户活动。应用程序不会关心调用是立即完成还是几秒钟后完成。

顺便说一句,市场上的一种产品提供了一种策略驱动的方法,允许异步调用,就像我描述的那样,进行异步调用(http://www.heimdalldata.com/)。免责声明: 我是本公司的联合创始人。它允许将正则表达式应用于任何 JDBC 数据源的插入/更新/删除等数据转换请求,并自动将它们批处理在一起。当与 MySQL 和 rewriteBatpedStatments 选项(MySQL 和 JDBC 使用 rewriteBatechStatments = true)一起使用时,这可以显著降低数据库的总体负载。

在我看来,你有三个选择:

  1. 使用 并行队列将消息分布在固定数量的少量线程上。因此,如果您有1000个连接,您将有4个线程,而不是1000个线程。
  2. 对另一个节点(即另一个进程或机器)执行数据库访问,并让数据库客户机对该节点执行 异步网络调用操作。
  3. 通过异步消息实现真正的分布式系统。为此,您将需要一个消息队列,如 CoralMQ 或 Tibco。

我是 CoralMQ 的开发者之一。

下面是在 JavaOne 上展示的 Oracle 的非阻塞 jdbc api 的轮廓: Https://static.rainfocus.com/oracle/oow16/sess/1461693351182001emrq/ppt/conf1578%2020160916.pdf

因此,最终看来,真正的异步 JDBC 调用确实是可能的。

看起来一个新的异步 jdbcAPI“ JDBC next”正在开发中。

参见 在这里展示

您可以从 给你下载 API

更新:

如果您对 Java 的异步数据库 API 感兴趣,那么您应该知道有一个新的倡议,即提出一组基于 CompletableFuture 和 lambdas 的标准 API。还有一种通过 JDBC 实现这些 API 的方法,可以用来实践这些 API: Https://github.com/oracle/oracle-db-examples/tree/master/java/aoj 在 github 项目的 README 中提到了 JavaDoc。

正如在其他答案中提到的,JDBC API 本质上不是异步的。
但是,如果您可以使用操作的子集和不同的 API,那么就有解决方案。一个例子是适用于 MySQL 和 PostgreSQL 的 https://github.com/jasync-sql/jasync-sql

目前正在开发一种解决方案,使标准关系数据库的反应性连接成为可能。

人们希望在保留关系数据库使用的同时扩展规模 由于现行的标准,响应式编程被切断 R2DBC 指定了一个允许反应代码的新 API 有效地处理关系数据库。

R2DBC 是一个从头到尾为反应设计的规范 使用 SQL 数据库定义非阻塞 SPI 进行编程 数据库驱动程序实现程序和客户端库作者 在非阻塞的基础上完全实现数据库连接协议 I/O 层。

R2DBC 的网站

R2DBC 的 GitHub

特征矩阵

enter image description here