¿Es posible la llamada jdbc asincrónica?

Me pregunto si hay una manera de hacer llamadas asíncronas a una base de datos.

Por ejemplo, imagine que tengo una gran solicitud que lleva mucho tiempo procesar, quiero enviar la solicitud y recibir una notificación cuando la solicitud devuelva un valor (pasando un Listener / callback o algo así). No quiero bloquear esperando a que la base de datos responda.

No considero que el uso de un grupo de subprocesos sea una solución porque no se escala, en el caso de solicitudes concurrentes pesadas esto generará una gran cantidad de subprocesos.

Nos enfrentamos a este tipo de problema con los servidores de red y hemos encontrado soluciones al utilizar la llamada al sistema select / poll / epoll para evitar tener un hilo por conexión. Me pregunto cómo tener una función similar con la solicitud de la base de datos.

Nota: Soy consciente de que usar FixedThreadPool puede ser una buena solución, pero me sorprende que nadie haya desarrollado un sistema realmente asincrónico (sin el uso de un hilo adicional).

** Actualización **
Debido a la falta de soluciones prácticas reales, decidí crear una biblioteca (parte de finagle): finagle-mysql . Básicamente decodifica / decodifica solicitud / respuesta de mysql y usa Finagle / Netty debajo del capó. Se escala extremadamente bien incluso con una gran cantidad de conexiones.

No entiendo cómo alguno de los enfoques propuestos que envuelven las llamadas JDBC en Actores, ejecutores o cualquier otra cosa puede ayudar aquí. ¿Alguien puede aclararlo?

Seguramente el problema básico es que las operaciones JDBC bloquean en el socket IO. Cuando lo hace, bloquea el hilo que se ejecuta: el final de la historia. Cualquiera que sea el marco de ajuste que elijas usar, terminará con un hilo que se mantendrá ocupado / bloqueado por solicitud simultánea.

Si los controladores de base de datos subyacentes (MySql?) Ofrecen un medio para interceptar la creación del socket (ver SocketFactory), entonces me imagino que sería posible construir una capa de base de datos basada en eventos asíncronos sobre la api JDBC, pero tendríamos que encapsular JDBC entero detrás de una fachada impulsada por un evento, y esa fachada no se vería como JDBC (después de que sería impulsada por eventos). El procesamiento de la base de datos se realizaría de forma asincrónica en un hilo diferente para la persona que llama, y ​​usted tendría que encontrar la forma de construir un administrador de transacciones que no dependa de la afinidad del hilo.

Algo así como el enfoque que menciono permitiría que incluso un solo hilo de fondo procesara una carga de ejecutivos simultáneos de JDBC. En la práctica, probablemente ejecute un conjunto de hilos para hacer uso de múltiples núcleos.

(Por supuesto, no estoy comentando la lógica de la pregunta original solo las respuestas que implican que la concurrencia en un escenario con IO de socket de locking es posible sin el usuario de un patrón de selector, más simple simplemente resolver su concurrencia de JDBC típica y poner en un grupo de conexión del tamaño correcto).


Parece que MySql probablemente hace algo en la línea que estoy sugiriendo — http://code.google.com/p/async-mysql-connector/wiki/UsageExample

Es imposible realizar una llamada asincrónica a la base de datos a través de JDBC, pero puede realizar llamadas asíncronas a JDBC con Actores (por ejemplo, el actor realiza llamadas al DB a través de JDBC y envía mensajes a los terceros cuando finalizan las llamadas), o, si le gusta CPS, con futuros segmentados (promesas) (una buena implementación es Scalaz Promises )

No considero que el uso de un grupo de subprocesos sea una solución porque no se escala, en el caso de solicitudes concurrentes pesadas esto generará una gran cantidad de subprocesos.

Los actores de Scala por defecto están basados ​​en eventos (no basados ​​en subprocesos): la progtwigción de continuación permite crear millones de actores en una configuración de JVM estándar.

Si tiene como objective Java, Akka Framework es una implementación de modelo Actor que tiene una buena API tanto para Java como para Scala.


Aparte de eso, la naturaleza sincrónica de JDBC tiene mucho sentido para mí. El costo de una sesión de base de datos es mucho más alto que el costo de la cadena Java que se está bloqueando (ya sea en primer plano o en segundo plano) y esperando una respuesta. Si sus consultas se ejecutan durante tanto tiempo que las capacidades de un servicio de ejecutor (o envolviendo los marcos de concurrencia Actor / fork-join / promise) no son suficientes para usted (y está consumiendo demasiados hilos) primero debe pensar en su carga de la base de datos Normalmente, la respuesta de una base de datos vuelve muy rápido, y un servicio ejecutor respaldado con un grupo de subprocesos fijo es una solución lo suficientemente buena. Si tiene demasiadas consultas de larga ejecución, debe considerar el procesamiento previo (pre), como el recálculo nocturno de los datos o algo así.

Tal vez podría utilizar un sistema de mensajería asíncrona JMS, que se escala bastante bien, en mi humilde opinión:

  • Envíe un mensaje a una cola, donde los suscriptores aceptarán el mensaje y ejecutarán el proceso de SQL. Su proceso principal continuará ejecutándose y aceptando o enviando nuevas solicitudes.

  • Cuando finaliza el proceso de SQL, puede ejecutar la ruta opuesta: enviar un mensaje a una ResponseQueue con el resultado del proceso, y un oyente del lado del cliente lo acepta y ejecuta el código de callback.

No hay soporte directo en JDBC pero tiene múltiples opciones como MDB, ejecutores de Java 5.

“No considero que usar un conjunto de hilos sea una solución porque no escala, en el caso de solicitudes concurrentes pesadas esto generará una gran cantidad de hilos”.

Tengo curiosidad por saber por qué un conjunto limitado de hilos no va a escalar? Es un grupo, no thread-per-request, para engendrar un hilo por cada solicitud. He estado usando esto durante bastante tiempo en una aplicación de carga pesada y hasta ahora no hemos visto ningún problema.

Los ejecutores de Java 5.0 pueden ser útiles.

Puede tener un número fijo de hilos para manejar operaciones de larga ejecución. Y en lugar de Runnable , puede usar Callable , que devuelve un resultado. El resultado se encapsula en un objeto Future , por lo que puede obtenerlo cuando vuelva.

El proyecto Ajdbc parece responder a este problema http://code.google.com/p/adbcj/

Actualmente hay 2 controladores asincrónicos nativos experimentales para mysql y postgresql.

Una vieja pregunta, pero algo más de información. No es posible hacer que JDBC emita solicitudes asincrónicas a la base de datos, a menos que un proveedor proporcione una extensión a JDBC y un contenedor para manejar JDBC. Dicho esto, es posible ajustar JDBC con una cola de procesamiento e implementar una lógica que pueda procesar la cola en una o más conexiones separadas. Una ventaja de esto para algunos tipos de llamadas es que la lógica, si está suficientemente cargada, podría convertir las llamadas en lotes JDBC para su procesamiento, lo que puede acelerar la lógica significativamente. Esto es más útil para las llamadas donde se están insertando datos, y el resultado real solo se debe registrar si hay un error. Un buen ejemplo de esto es si se realizan inserciones para registrar la actividad del usuario. A la aplicación no le importará si la llamada finaliza inmediatamente o dentro de unos segundos.

Como nota al margen, un producto en el mercado ofrece un enfoque basado en políticas para permitir que las llamadas asíncronas como las que describí se hagan de forma asíncrona ( http://www.heimdalldata.com/ ). Descargo de responsabilidad: soy cofundador de esta empresa. Permite aplicar expresiones regulares a las solicitudes de transformación de datos, como insertar / actualizar / eliminar para cualquier fuente de datos JDBC, y las agrupará automáticamente para su procesamiento. Cuando se utiliza con MySQL y la opción rewriteBatchedStatements ( MySQL y JDBC con rewriteBatchedStatements = true ), esto puede reducir significativamente la carga general en la base de datos.

Parece que una nueva API jdbc asincrónica “JDBC next” está en proceso.

Vea la presentación aquí

Puedes descargar la API desde aquí

Tienes tres opciones en mi opinión:

  1. Use una cola simultánea para distribuir mensajes a través de un número pequeño y fijo de hilos. Entonces, si tiene 1000 conexiones, tendrá 4 hilos, no 1000 hilos.
  2. Haga el acceso a la base de datos en otro nodo (es decir, otro proceso o máquina) y haga que su cliente de base de datos realice llamadas de red asincrónicas a ese nodo.
  3. Implementar un verdadero sistema distribuido a través de mensajes asíncronos. Para eso necesitarás una cola de mensajes como CoralMQ o Tibco.

Diclaimer: soy uno de los desarrolladores de CoralMQ.

Simplemente una idea loca: podrías usar un patrón Iteratee sobre JBDC resultSet envuelto en Future / Promise

Hammersmith hace eso por MongoDB .

Solo estoy pensando ideas aquí. ¿Por qué no podrías tener un conjunto de conexiones de bases de datos con cada una de ellas teniendo un hilo? Cada hilo tiene acceso a una cola. Cuando quiere hacer una consulta que lleva mucho tiempo, puede poner la cola y luego uno de los hilos la recogerá y manejará. Nunca tendrá demasiados hilos porque la cantidad de hilos está limitada.

Editar: O mejor aún, solo una cantidad de hilos. Cuando un hilo ve algo en una cola, solicita una conexión del grupo y lo maneja.

La biblioteca commons-dbutils admite un AsyncQueryRunner que le proporciona un ExecutorService y devuelve un Future . Vale la pena echarle un vistazo ya que es fácil de usar y garantiza que no se perderán recursos.

Aquí hay un resumen sobre cómo se vería una api jdbc sin locking de Oracle presentada en JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf

Por lo tanto, parece que, al final, realmente serán posibles las llamadas JDBC verdaderamente asíncronas.

Si está interesado en las API de bases de datos asíncronas para Java, debe saber que existe una nueva iniciativa para crear un conjunto de API estándar basadas en CompletableFuture y lambdas. También hay una implementación de estas API sobre JDBC que se puede utilizar para practicar estas API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ El JavaDoc se menciona en el archivo README de el proyecto github.