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

时间:2010-11-03 13:52:18

标签: java scala jdbc asynchronous nonblocking

我想知道是否有办法对数据库进行异步调用?

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

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

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

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

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

16 个答案:

答案 0 :(得分:152)

我不明白在演员,执行者或其他任何东西中包含JDBC调用的任何提议方法如何在这里有所帮助 - 有人可以澄清。

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

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

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

(当然我没有评论原始问题的逻辑,只是意味着在没有选择器模式的用户的情况下可以在具有阻塞套接字IO的情况下实现并发的响应 - 只是为了解决典型的JDBC问题并发并放入正确大小的连接池。


看起来MySql可能会像我建议的那样做点什么--- http://code.google.com/p/async-mysql-connector/wiki/UsageExample

答案 1 :(得分:40)

通过JDBC对数据库进行异步调用是不可能的,但您可以使用 Actors 进行异步调用(例如, actor通过JDBC调用数据库,并在调用结束时向第三方发送消息,或者,如果你喜欢CPS,则调用pipelined futures (promises)(一个好的实现是Scalaz {{3 }})

  

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

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

如果您的目标是Java,Promises是一个Actor模型实现,它具有适用于Java和Scala的良好API。


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

答案 2 :(得分:10)

也许您可以使用JMS异步消息系统,它可以很好地扩展,恕我直言:

  • 向队列发送消息,订阅者将接受该消息,并运行SQL进程。您的主要流程将继续运行并接受或发送新请求。

  • 当SQL进程结束时,您可以以相反的方式运行:使用进程的结果向ResponseQueue发送消息,并且客户端的侦听器接受它并执行回调代码。

答案 3 :(得分:7)

JDBC中没有直接的支持,但您有多个选项,如MDB,Java 5的执行程序。

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

我很好奇为什么有限的线程池不会扩展?它是一个池而不是每个请求的线程,每个请求产生一个线程。我一直在重负载webapp上使用它,到目前为止我们还没有看到任何问题。

答案 4 :(得分:4)

它看起来像是一个新的异步jdbc API“JDBC next”正在开发中。

请参阅presentation here

您可以从here

下载API

答案 5 :(得分:4)

如其他答案所述,JDBC API本质上不是异步的。
但是,如果您可以使用部分操作和其他API,那么可以找到解决方案。一个示例是https://github.com/jasync-sql/jasync-sql,适用于MySQL和PostgreSQL。

答案 6 :(得分:3)

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

目前有2个用于mysql和postgresql的实验性本机异步驱动程序。

答案 7 :(得分:3)

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

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

答案 8 :(得分:3)

我认为你有三种选择:

  1. 使用concurrent queue在较小且固定数量的线程上分发邮件。因此,如果你有1000个连接,你将有4个线程,而不是1000个线程。
  2. 在另一个节点(即另一个进程或计算机)上进行数据库访问,并让数据库客户端向该节点发送asynchronous network calls
  3. 通过异步消息实现真正的分布式系统。为此,您需要一个消息队列,例如CoralMQ或Tibco。
  4. Diclaimer:我是CoralMQ的开发者之一。

答案 9 :(得分:2)

Java 5.0 executors可能会派上用场。

您可以拥有固定数量的线程来处理长时间运行的操作。而不是Runnable,您可以使用返回结果的Callable。结果封装在Future<ReturnType>对象中,因此您可以在它返回时获取它。

答案 10 :(得分:2)

只是一个疯狂的想法:你可以使用包含在一些Future / Promise中的JBDC resultSet上的Iteratee模式

Hammersmith为 MongoDB 做到了这一点。

答案 11 :(得分:1)

我只是在想这里的想法。为什么不能拥有一个数据库连接池,每个数据库连接都有一个线程。每个线程都可以访问队列。当你想做一个需要很长时间的查询时,你可以放入队列,然后其中一个线程将把它拿起并处理它。你永远不会有太多线程,因为你的线程数是有界限的。

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

答案 12 :(得分:1)

commons-dbutils库支持AsyncQueryRunner,您提供ExecutorService并返回Future。值得一试,因为它易于使用并确保您不会泄漏资源。

答案 13 :(得分:1)

如果您对Java的异步数据库API感兴趣,您应该知道有一个新的计划来提出一组基于CompletableFuture和lambdas的标准API。还有一些基于JDBC的API实现,可用于实践这些API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ 在github项目的README中提到了JavaDoc。

答案 14 :(得分:1)

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

  

希望在扩展规模的同时保留使用关系数据库的人们   由于基于现有的标准,因此无法进行反应式编程   阻止I / O。 R2DBC指定了一个新的API,该API允许使用响应代码   与关系数据库一起有效地工作。

     

R2DBC是专为无功设计的规范   使用SQL数据库进行编程以定义一个非阻塞SPI   数据库驱动程序实现者和客户端库作者。 R2DBC驱动程序   在非阻塞的基础上完全实现数据库有线协议   I / O层。

R2DBC's WebSite

R2DBC's GitHub

功能列表

enter image description here

答案 15 :(得分:-1)

一些简单的解决方案是将jdbs调用包装到CompletableFuture中,并为这些调用提供自定义线程池。