Temos um sistema pelo qual a conexão com o banco de dados é obtida uma vez usando um método comum e sendo transmitida por toda a classe relevante a ser usada. Há dúvidas de que a passagem da conexão com o banco de dados como parâmetro para diferentes classes possa causar problemas, por isso estou verificando aqui se isso é realmente viável e se existem padrões melhores para isso?
Eu sei que existem algumas ferramentas ORM para persistir, mas ainda não podemos entrar nisso.
Qualquer feedback é bem-vindo, obrigado.
java
database
patterns-and-practices
ipohfly
fonte
fonte
Respostas:
Sim, é seguro passar por uma conexão. Você lida com a conexão em um bloco de controle externo. Não há nada de inseguro nisso.
O que é inseguro é escrever um código que não garanta que a conexão seja descartada adequadamente em tempo hábil. Esquecer-se de limpar um recurso não tem relação com a distribuição. Você poderia escrever com a mesma facilidade o código que deixa uma conexão interrompida sem transmiti-lo a qualquer lugar.
No C ++, você está protegido pelo RAII se alocar na pilha ou usar ponteiros inteligentes. Em C #, faça uma regra rígida de que todos os objetos descartáveis (como conexões) sejam declarados em um bloco "using". Em Java, limpe com a lógica try-finally. Faça revisões de código em todo o código da camada de dados para garantir isso.
O caso de uso mais comum é quando você tem várias operações que podem ser combinadas em várias permutações. E cada uma dessas permutações precisa ser uma transação atômica (todas com êxito ou reversão). você deve passar a transação (e, portanto, a conexão correspondente) para todos os métodos.
Suponha que tenhamos muitas ações foobar () que podem ser combinadas de várias maneiras como transações atômicas.
BTW, você desejará abrir as conexões o mais tarde possível, descartá-las o mais rápido possível. Seus colegas de equipe podem estar certos se você estiver tratando as conexões como membros do objeto, introduzindo-as como um estado desnecessário e deixando as conexões abertas por muito mais tempo do que o necessário. Mas o ato de passar uma conexão ou transação como parâmetro não é inerentemente errado.
Entre. Dependendo do suporte do seu idioma às funções de primeira classe, você poderá executar uma lista de ações foobar (). Portanto, uma função pode lidar com todas as permutações das ações. Eliminando a duplicação do bloco de controle externo para cada permutação.
fonte
Parece que você está após a injeção de dependência . Ou seja, a conexão em pool é criada uma vez e injetada onde for necessário. Certamente, passar a conexão através de um parâmetro de método é uma maneira de injetar dependência, mas um contêiner de IoC, como Guice, PicoContainer ou Spring, é outra maneira (mais segura) de fazer isso.
O uso do DI significa que você pode agrupar perfeitamente a lógica em torno da criação, abertura, uso e fechamento da conexão - longe da lógica de negócios principal.
Spring JDBC et al. São outros exemplos de como executar esse tipo de comportamento para você
fonte
Passar coisas do banco de dados em vez de dados pode levar a problemas. Nessa medida, sempre que possível, não passe uma coisa do banco de dados, a menos que se possa garantir uma higiene adequada do banco de dados.
O problema de repassar as coisas do banco de dados é que ele pode ser desleixado. Eu vi mais de um bug no código com alguém passando por uma conexão com o banco de dados, que alguém pega um conjunto de resultados e oculta em um objeto local (o conjunto de resultados ainda conectado ao banco de dados) e amarra um cursor no banco de dados por um tempo significativo. Outra instância em que alguém passou um conjunto de resultados para outra pessoa (que foi ocultada) e, em seguida, o método que passou o conjunto de resultados fechou (e a instrução) levando a erros quando outros métodos tentaram trabalhar com o conjunto de resultados que não era mais.
Tudo isso decorre de não respeitar o banco de dados, a conexão, a instrução, o conjunto de resultados e seus ciclos de vida.
Para evitar isso, existem padrões e estruturas existentes que funcionam mais bem com os bancos de dados e não possuem dados necessários para sair das classes em que estão confinados. Os dados entram, os dados saem e o banco de dados permanece em uso.
fonte
Root
um Dao. Mas então você percebe que também quer uma maneira de obter umaNode
sem puxar oRoot
objeto inteiro com ela. Como você faz oRoot
Dao chamar oNode
código do Dao (ou seja, reutilizar), mas verifique se oNode
Dao fecha a conexão apenas quando oNode
Dao é chamado diretamente e mantém a conexão aberta quando oRoot
Dao é chamado?Passar
Connection
instâncias ao redor geralmente não é um problema, embora na maioria das situações apenas as implementações do DAO devam ter algo a ver com elas. Agora, com o problema de as conexões não serem fechadas após o uso, é realmente fácil de corrigir: oConnection
objeto precisa ser fechado no mesmo nível em que é aberto, ou seja, no mesmo método. Eu pessoalmente uso o seguinte padrão de código:Dessa forma, garanto que todas as conexões estejam sempre fechadas, mesmo que uma exceção seja lançada dentro do bloco. Na verdade, continuo usando o mesmo padrão
Statement
eResultSet
instâncias, e tudo tem sido tranquilo até agora.Edite 29-03-2018: Conforme indicado pelo usuário1156544 nos comentários abaixo, a partir do Java 7, o uso da construção try-with-resources deve ser favorecido. Utilizando-o, o padrão de código que forneci na minha resposta inicial pode ser simplificado da seguinte forma:
fonte
dataSource
vez deDataSource
(vou corrigir minha resposta sobre esse ponto). O tipo exato desse objeto seriajavax.sql.DataSource
. No código antigo, eu costumava ter um singleton gerenciar todas as fontes de dados disponíveis em meus aplicativos. Meus DAOs não precisavam saber disso, pois aDataSource
instância é fornecida por injeção de dependência.existe uma desvantagem em fazer as coisas dessa maneira, em vez de usar um singleton que você pode obter conforme necessário. Eu fiz as coisas nos dois sentidos no passado.
Em geral, você precisa pensar nas consequências do gerenciamento de conexões com o banco de dados, e isso pode ou não ser ortogonal ao uso da consulta ao banco de dados. Por exemplo, se você tiver uma conexão db para uma determinada instância do aplicativo e ela for fechada quando não estiver em uso, isso será ortogonal. Coloque o gerenciamento em uma classe única e não o repasse. Isso permite que você gerencie a conexão db conforme necessário. Por exemplo, se você deseja fechar uma conexão em cada confirmação (e reabrir na próxima chamada), isso é mais fácil em um singleton, porque a API para isso pode ser centralizada.
Por outro lado, suponha que você precise gerenciar um conjunto de conexões em que uma determinada chamada possa precisar usar qualquer conexão arbitrária. Isso pode acontecer ao fazer transações distribuídas em vários servidores, por exemplo. Nesse caso, geralmente é melhor passar o objeto de conexão db do que trabalhar com singletons. Eu acho que esse geralmente é o caso mais raro, mas não há nada de errado em fazer isso quando você precisa.
fonte