Estou desenvolvendo um sistema com servlets e JDBC. Entre a servlet e o DAO tenho um Service que é responsável por dar commit quando tudo der certo e Rollback quando algo de errado…
Porém tenho percebido que o sistema esta abrindo várias conexões no banco de dados e não estão sendo fechadas. Claro, por que realmente não estou fechando… porém não estou sabendo onde fechá-las… Veja um exemplo do meu Service…
public class VisitorService {
private Connection connection = new ConnectionDBFactory().getConnection();
private VisitorDao visitorDao = new VisitorDao(connection);
Se depois do commit eu colocar um connection.close(), e no meu servlet eu tiver duas chamadas a este Service… obviamente a segunda chamada da erro…pq a conexão esta fechada… não estou sabendo onde fechar a conexão!
Em que momento você abre a conexão, na instanciação do Servlet?
Você poderia abrir a conexão quando o serviço é solicitado, preparar o retorno e fechar a conexão, mas isso pode fazer seu serviço ficar lento.
Poderia sobrescrever os métodos init e destroy da classe Servlet.
Inicializar a conexão dentro do método init e fechar dentro do método destroy.
I
igomes
poque está dando commit ? o seu get está alterando algo ? o certo seria fechar no seu próprio dao ou talvez criar um filter.
Não entendo nem porque essa connection esta sendo passada como parametro, isola logo ela dentro do dao
vai ficar repetindo esse código a cada service ?
S
staroski
É fogo @igomes, vejo muitos colegas que fazem isso, o pior é que os professores ensinam dessa forma…
Ou seja, jogam a abstração e encapsulamento no lixo.
P
picklesdog70
Estou usando um service para dar o commit ou o rollback e não no DAO pq tenho situações que preciso inserir ou alterar varias tabelas…ou seja… preciso garantir que tudo foi feito ou nada foi feito… se eu deixar com auto commit ou commit no método do DAO… se algo der errado no meio…algumas coisas ja estarão commitadas, correto? Por usar esse service antes do DAO criei a conexão nele e nao no DAO…
Mas estou aberto a sugestões…
R
Ricardo_Machado2
Em algum lugar você chama explicitamente new VisitorService() ?
Cada vez que você fizer isso ele vai abrir uma conexão pelo que eu estou entendo,
cada vez que ele faz
private Connection connection = new ConnectionDBFactory().getConnection();
ele abre uma conexão, você pode trabalhar com uma conexão aberta só, garantindo que o getConnection seja chamado só uma vez, usando uma estrategia singleton.
ou utilizar alguma biblioteca para gerenciar os seus pulls de conexão.
P
picklesdog70
Sim… no Servlet eu faço esse new…
J
javaflex
Considerando que na sua infraestrutura de conexão seja algo parecido com pelo menos esse exemplo simples:
publicList<Tipo>atenderRequisicaoXYZ()throwsException{Connectionconnection=newConnectionFactory().getConnection();try{//sua lógica...//como já avisaram, não precisa de commit no caso de selects!}}finally{connection.close();}
Obs.: É um exemplo mais simples possível. Considerando que o seu método seja o método principal que atende a resposta final da funcionalidade. Desta forma haverá somente 1 conexão aberta durante todo o processamento da funcionalidade requisitada via HTTP pelo servlet.
Lembrando que naturalmente Web não tem estado, a cada requisição será aberta uma nova conexão com o banco, sendo que assim que terminar de acessar o banco deverá fechar a conexão.
P
picklesdog70
É exatamente isso…a única diferença esta que :
Connection connection = new ConnectionFactory().getConnection();
eu instancio junto com a classe e não a cada método…
J
javaflex
Então o problema pode ser em outro lugar que voce não tenha mostrado.
@WebServlet("/income")publicclassIncomeServletextendsHttpServlet{privateIncomeServiceincomeService=newIncomeService();@OverrideprotectedvoiddoPost(HttpServletRequestreq,HttpServletResponseres)throwsServletException,IOException{//SETs da income.....incomeService.insert(income);}}
Acredito que você tenha resolvido o meu problema quando sugeriu que eu fizesse Connection connection = new ConnectionDBFactory().getConnection(); e um connection.close() a cada método e não um Connection connection = new ConnectionDBFactory().getConnection(); na instancia do Service.
Só ficou uma pequena dúvida, quanto a repetição do Connection connection = new ConnectionDBFactory().getConnection(); a cada método. Acha que eu poderia melhorar isso?
J
Solucao aceita
javaflex1 like
Tem várias formas. A tentativa mais próxima do que você está fazendo seria assim:
publicclassVisitorService{privateConnectionconnection;privateVisitorDaovisitorDao;publicVisitorService(){connection=newConnectionDBFactory().getConnection();visitorDao=newVisitorDao(connection);}@Overridepublicvoidfinalize()throwsThrowable{connection.Close();super.finalize();//ver se é necessário}publicList<Visitor>getVisitorsTodayWithoutExit()throwsException{List<Visitor>visitors=visitorDao.getVisitorsTodayWithoutExit();returnvisitors;}}
Só não tenho como garantir isso, usar finalize() não é recomendado. Coloque um breakpoint no connection.Close() pra ver se ele realmente vai fechar a conexão no momento que você espera, pois vai depender do imprevisível garbage collection, por isso não é recomendado. Do jeito que te passei antes com finally que é o garantido.