asynchronous的jdbc调用是可能的吗?
我想知道是否有办法对数据库进行asynchronous调用?
例如,假设我有一个需要很长时间处理的大请求,我想发送请求,并在请求返回一个值(通过传递一个监听器/callback或其他)时收到一个通知。 我不想阻止等待数据库回答。
我不认为使用线程池是一个解决scheme,因为它不扩展,在繁重的并发请求的情况下,这将产生大量的线程。
我们正面临networking服务器的这种问题,我们通过使用select / poll / epoll系统调用来find解决scheme,以避免每个连接有一个线程。 我只是想知道如何有一个类似的function与数据库请求?
注:我知道使用FixedThreadPool可能是一个很好的解决方法,但我很惊讶没有人开发出一个真正asynchronous的系统(没有使用额外的线程)。
**更新**
由于缺乏切实可行的解决scheme,我决定自己创build一个库(finagle的一部分): finagle-mysql 。 它基本上解码/解码MySQL的请求/响应,并使用Finagle / Netty下的。 即使有大量的连接,它也能很好地扩展。
我不明白如何在演员,执行者或任何其他包装JDBC调用提出的方法可以帮助在这里 – 有人可以澄清。
当然,基本的问题是,JDBC操作在套接字IO上阻塞。 当它这样做时,它会阻止线程运行在故事结尾。 无论您select使用哪一个包装框架,最终都会导致一个线程按并发请求保持忙/阻塞状态。
如果底层的数据库驱动程序(MySql?)提供了一个拦截套接字创build的方法(参见SocketFactory),那么我想可以在JDBC API上构build一个asynchronous事件驱动的数据库层,但是我们必须封装整个JDBC在事件驱动的外观之后,并且外观看起来不像JDBC(在事件驱动之后)。 数据库处理将在与调用方不同的线程上发生asynchronous,您将不得不研究如何构build不依赖线程关系的事务pipe理器。
就像我提到的方法,甚至可以让一个后台线程处理并发JDBC exec的负载。 在实践中,你可能会运行一个线程池,以利用多个核心。
(当然,我没有评论原始问题的逻辑,只是意味着在没有select器模式的用户的情况下,可能会发生并发性的阻塞套接字IO的响应 – 只是简单地解决典型的JDBC并发问题在正确大小的连接池中)。
看起来像MySql可能会沿着我build议的东西— http://code.google.com/p/async-mysql-connector/wiki/UsageExample
通过JDBC 对数据库进行asynchronous调用是不可能的,但是您可以使用Actors 对JDBC进行asynchronous调用(例如,actor通过JDBC调用数据库,并在调用结束时向第三方发送消息),或者,如果你喜欢CPS,用stream水线期货(承诺) (一个很好的实现是斯卡拉斯 承诺 )
我不认为使用线程池是一个解决scheme,因为它不扩展,在繁重的并发请求的情况下,这将产生大量的线程。
默认情况下,Scala actor是基于事件(不是基于线程的) – 延续调度允许在标准的JVM设置上创build数以百万计的angular色。
如果您的目标是Java, Akka Framework是一个Actor模型实现,它具有用于Java和Scala的良好API。
除此之外,JDBC的同步性对我来说是完全有意义的。 数据库会话的成本远高于被阻塞的Java线程的成本(在前台或后台)并等待响应。 如果你的查询运行时间过长,以至于executor服务(或者包装Actor / fork-join / promise并发框架)的function对于你来说还不够(而且你消耗太多的线程),那么首先应该考虑一下你的数据库负载。 通常来自数据库的响应速度非常快,并且使用固定线程池支持的执行程序服务是一个足够好的解决scheme。 如果你有太多的长时间运行的查询,你应该考虑预先处理 – 就像每晚重新计算数据或类似的东西。
也许你可以使用JMSasynchronous消息传递系统,这个系统可以很好地扩展,恕我直言:
-
将消息发送到订阅者将接受消息的队列,然后运行SQL进程。 您的主进程将继续运行并接受或发送新的请求。
-
当SQL进程结束时,可以以相反的方式运行:发送消息到带有进程结果的ResponseQueue,并且客户端上的侦听器接受它并执行callback代码。
在JDBC中没有直接的支持,但是你有多个选项,比如来自Java 5的MDB,Executors。
“我不认为使用线程池是一个解决scheme,因为它不能扩展,在繁重的并发请求的情况下,这将产生大量的线程。”
我很好奇,为什么一个有限的线程池不会扩展? 它是一个不是每个线程请求的线程来为每个请求产生一个线程。 我一直使用这个在一个重载Web应用程序的相当一段时间,我们目前还没有看到任何问题。
Java 5.0执行者可能会得心应手。
您可以拥有固定数量的线程来处理长时间运行的操作。 而不是Runnable
你可以使用Callable
来返回一个结果。 结果被封装在一个Future<ReturnType>
对象中,所以当它返回时你可以得到它。
Ajdbc项目似乎回答了这个问题http://code.google.com/p/adbcj/
目前有2个用于mysql和postgresql的本地实验asynchronous驱动程序。
一个古老的问题,但更多的信息。 除非供应商提供JDBC扩展和用来处理JDBC的包装器,否则JDBC不可能向数据库本身发出asynchronous请求。 也就是说,可以用一个处理队列来包装JDBC本身,并实现可以在一个或多个独立连接上处理队列的逻辑。 对于某些types的调用来说,这样做的一个优点是,如果负载足够大,逻辑可以将调用转换为批处理进行处理,这可以显着加速逻辑。 这对插入数据的调用非常有用,只有在出现错误时才需要logging实际结果。 一个很好的例子就是如果正在执行插入logging用户活动。 应用程序不会在意立即或几秒后立即完成呼叫。
作为一个侧面说明,市场上的一种产品提供了一种策略驱动的方法,允许asynchronous调用(如我所描述的asynchronous调用)( http://www.heimdalldata.com/ )。 免责声明:我是这家公司的联合创始人。 它允许将正则expression式应用于数据转换请求,例如插入/更新/删除任何JDBC数据源,并将自动批量处理。 当使用MySQL和rewriteBatchedStatements选项( MySQL和JDBC with rewriteBatchedStatements = true )时,这可以显着降低数据库的总体负载。
只是一个疯狂的想法:你可以使用包装在Future / Promise中的JBDC resultSet的Iteratee模式
哈默史密斯是为MongoBd做的。
我认为你有三个select:
- 使用一个并发队列来分布消息在一小部分固定数量的线程上。 所以如果你有1000个连接,你将有4个线程,而不是1000个线程。
- 在另一个节点(即另一个进程或机器)上执行数据库访问,让数据库客户端对该节点进行asynchronousnetworking调用 。
- 通过asynchronous消息实现真正的分布式系统。 为此,您将需要一个消息队列,如CoralMQ或Tibco。
Diclaimer:我是CoralMQ的开发者之一。
我只是在想这个想法。 为什么你不能有一个数据库连接池,每个人都有一个线程。 每个线程都可以访问一个队列。 当你想要做一个需要很长时间的查询的时候,你可以把它放在队列中,然后其中的一个线程会把它拿起来处理。 你永远不会有太多的线程,因为你的线程数是有限的。
编辑:或者更好,只是一些线程。 当一个线程看到某个队列中的某个东西时,它要求从该池中build立一个连接并处理它。
commons-dbutils库支持您提供ExecutorService
的AsyncQueryRunner
,并返回Future
。 值得检查,因为它使用简单,并确保你不会泄漏资源。