Gostaria de saber se existe uma maneira de fazer chamadas assíncronas para um banco de dados?
Por exemplo, imagine que eu tenho uma grande solicitação que leva muito tempo para processar. Quero enviar a solicitação e receber uma notificação quando a solicitação retornar um valor (passando um ouvinte / retorno de chamada ou algo assim). Não quero bloquear a espera pela resposta do banco de dados.
Não considero que o uso de um pool de threads seja uma solução, pois não é dimensionável; no caso de solicitações simultâneas pesadas, isso gera um número muito grande de threads.
Estamos enfrentando esse tipo de problema com os servidores de rede e encontramos soluções usando a chamada de sistema select / poll / epoll para evitar ter um encadeamento por conexão. Eu só estou querendo saber como ter um recurso semelhante com a solicitação de banco de dados?
Nota: Estou ciente de que o uso de um FixedThreadPool pode ser uma boa solução, mas estou surpreso que ninguém tenha desenvolvido um sistema realmente assíncrono (sem o uso de encadeamento extra).
** Atualização **
Devido à falta de soluções práticas reais, decidi criar uma biblioteca (parte do finagle): finagle-mysql . Basicamente, decodifica / decodifica a solicitação / resposta do mysql e usa o Finagle / Netty sob o capô. Escala extremamente bem, mesmo com um grande número de conexões.
fonte
Respostas:
Não entendo como qualquer uma das abordagens propostas que envolvem chamadas JDBC em atores, executores ou qualquer outra coisa pode ajudar aqui - alguém pode esclarecer.
Certamente o problema básico é que as operações JDBC são bloqueadas no soquete IO. Quando faz isso, ele bloqueia o Thread no final da história. Qualquer que seja a estrutura de agrupamento que você escolher, ela acabará com um encadeamento sendo ocupado / bloqueado por solicitação simultânea.
Se os drivers de banco de dados subjacentes (MySql?) Oferecerem um meio de interceptar a criação do soquete (consulte SocketFactory), imagino que seria possível criar uma camada de banco de dados assíncrona orientada a eventos sobre a API JDBC, mas teríamos que encapsular o JDBC inteiro atrás de uma fachada orientada a eventos, e essa fachada não se pareceria com JDBC (depois que seria orientada a eventos). O processamento do banco de dados aconteceria de maneira assíncrona em um encadeamento diferente do chamador, e você teria que descobrir como criar um gerenciador de transações que não depende da afinidade do encadeamento.
Algo parecido com a abordagem mencionada permitiria que mesmo um único encadeamento em segundo plano processasse uma carga de executivos JDBC simultâneos. Na prática, você provavelmente executaria um pool de threads para usar vários núcleos.
(É claro que não estou comentando a lógica da pergunta original, apenas as respostas que implicam que a simultaneidade em um cenário com IO de soquete de bloqueio é possível sem o usuário de um padrão seletor - é mais simples trabalhar com sua simultaneidade JDBC típica e colocar em um conjunto de conexões do tamanho certo).
Parece que o MySql provavelmente faz algo parecido com o que estou sugerindo --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample
fonte
É impossível fazer uma chamada assíncrona para o banco de dados via JDBC, mas você pode fazer chamadas assíncronas para o JDBC com atores (por exemplo, o ator faz chamadas para o banco de dados via JDBC e envia mensagens para terceiros quando as chamadas terminam), ou, se você gosta do CPS, com futuros em pipeline (promessas) (uma boa implementação é Scalaz Promises )
Os atores Scala, por padrão, são baseados em eventos (não em threads) - o agendamento de continuação permite criar milhões de atores em uma configuração JVM padrão.
Se você está direcionando para Java, o Akka Framework é uma implementação de modelo de ator que possui uma boa API para Java e Scala.
Além disso, a natureza síncrona do JDBC faz todo o sentido para mim. O custo de uma sessão de banco de dados é muito superior ao custo do encadeamento Java sendo bloqueado (em primeiro ou segundo plano) e aguardando uma resposta. Se suas consultas forem executadas por tanto tempo que os recursos de um serviço executor (ou agrupar estruturas de simultaneidade Actor / fork-join / promessa) não são suficientes para você (e você está consumindo muitos threads), primeiro pense em seu carga de banco de dados. Normalmente, a resposta de um banco de dados volta muito rapidamente, e um serviço executor suportado com um pool de threads fixo é uma solução boa o suficiente. Se você tiver muitas consultas de longa execução, considere o processamento inicial (pré-) - como recálculo noturno dos dados ou algo assim.
fonte
Talvez você possa usar um sistema de mensagens assíncrono JMS, que escala muito bem, IMHO:
Envie uma mensagem para uma Fila, na qual os assinantes aceitarão a mensagem e execute o processo SQL. Seu processo principal continuará em execução e aceitar ou enviar novas solicitações.
Quando o processo SQL termina, você pode executar o caminho oposto: envie uma mensagem para um ResponseQueue com o resultado do processo, e um ouvinte no lado do cliente o aceitará e executará o código de retorno de chamada.
fonte
Não há suporte direto no JDBC, mas você tem várias opções como MDB, Executors from Java 5.
"Não considero que o uso de um pool de threads seja uma solução, porque não é escalável. No caso de solicitações simultâneas pesadas, isso gera um número muito grande de threads".
Estou curioso por que um pool limitado de threads não será dimensionado? É um pool não encadeado por solicitação para gerar um encadeamento por cada solicitação. Eu tenho usado isso por algum tempo em um webapp de carga pesada e ainda não vimos nenhum problema.
fonte
Parece que uma nova API jdbc assíncrona "JDBC next" está em andamento.
Veja a apresentação aqui
Você pode baixar a API aqui
fonte
Conforme mencionado em outras respostas, a API do JDBC não é assíncrona por natureza.
No entanto, se você pode viver com um subconjunto de operações e uma API diferente, existem soluções. Um exemplo é https://github.com/jasync-sql/jasync-sql que funciona para MySQL e PostgreSQL.
fonte
O projeto Ajdbc parece responder a este problema http://code.google.com/p/adbcj/
Atualmente, existem 2 drivers nativos assíncronos experimentais para mysql e postgresql.
fonte
Uma pergunta antiga, mas mais algumas informações. Não é possível que o JDBC emita solicitações assíncronas para o próprio banco de dados, a menos que um fornecedor forneça uma extensão ao JDBC e um wrapper para lidar com o JDBC. Dito isso, é possível agrupar o próprio JDBC com uma fila de processamento e implementar lógica que possa processar a fila em uma ou mais conexões separadas. Uma vantagem disso para alguns tipos de chamadas é que a lógica, se for carregada o suficiente, pode converter as chamadas em lotes JDBC para processamento, o que pode acelerar significativamente a lógica. Isso é mais útil para chamadas em que os dados estão sendo inseridos e o resultado real precisa ser registrado apenas se houver um erro. Um ótimo exemplo disso é se inserções estão sendo executadas para registrar a atividade do usuário. O aplicativo ganhou '
Como observação lateral, um produto no mercado fornece uma abordagem orientada por políticas para permitir que chamadas assíncronas, como aquelas que descrevi, sejam feitas de maneira assíncrona ( http://www.heimdalldata.com/ ). Disclaimer: Eu sou co-fundador desta empresa. Ele permite que expressões regulares sejam aplicadas a solicitações de transformação de dados, como inserção / atualização / exclusões para qualquer fonte de dados JDBC, e as agrupará automaticamente em lote para processamento. Quando usado com o MySQL e a opção rewriteBatchedStatements ( MySQL e JDBC com rewriteBatchedStatements = true ), isso pode reduzir significativamente a carga geral no banco de dados.
fonte
Você tem três opções na minha opinião:
Diclaimer: Eu sou um dos desenvolvedores do CoralMQ.
fonte
Uma solução está sendo desenvolvida para possibilitar a conectividade reativa com bancos de dados relacionais padrão.
Site da R2DBC
GitHub do R2DBC
Matriz de recursos
fonte
Os executores do Java 5.0 podem ser úteis.
Você pode ter um número fixo de threads para lidar com operações de longa execução. E em vez de
Runnable
você pode usarCallable
, que retornam um resultado. O resultado é encapsulado em umFuture<ReturnType>
objeto, para que você possa obtê-lo quando voltar.fonte
Aqui está um resumo sobre como uma API jdbc não bloqueadora poderia ser da Oracle apresentada no JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf
Portanto, parece que, no final, chamadas JDBC verdadeiramente assíncronas serão realmente possíveis.
fonte
Apenas uma ideia maluca: você pode usar um padrão Iteratee sobre o resultado do JBDC
Hammersmith faz isso para o MongoDB .
fonte
Estou apenas pensando idéias aqui. Por que você não pode ter um pool de conexões com o banco de dados, cada um com uma thread. Cada encadeamento tem acesso a uma fila. Quando você quiser fazer uma consulta que demore muito, poderá colocar a fila e, em seguida, um dos threads a buscará e manipulará. Você nunca terá muitos threads porque o número de seus threads é limitado.
Edit: Ou melhor ainda, apenas um número de threads. Quando um thread vê algo em uma fila, solicita uma conexão do pool e lida com isso.
fonte
A biblioteca commons-dbutils possui suporte para um para o
AsyncQueryRunner
qual você fornece umExecutorService
para e retorna aFuture
. Vale a pena conferir, pois é simples de usar e garante que você não irá vazar recursos.fonte
Se você estiver interessado em APIs de banco de dados assíncronas para Java, saiba que existe uma nova iniciativa para criar um conjunto de APIs padrão baseadas em CompletableFuture e lambdas. Também há uma implementação dessas APIs sobre JDBC que pode ser usada para praticar essas APIs: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ O JavaDoc é mencionado no README do o projeto github.
fonte