Conexão fechada

13 respostas Resolvido
java
P

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);

public List getVisitorsTodayWithoutExit() throws Exception{

List visitors = visitorDao.getVisitorsTodayWithoutExit();

connection.commit();

return visitors;

}

}

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!

13 Respostas

S

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.

P

Abro aqui ó:

public class VisitorService {

    private Connection connection = new ConnectionDBFactory().getConnection();
S

Isso aí equivale a inicializar na instanciação. :slight_smile:

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

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

É 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

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

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

Sim… no Servlet eu faço esse new…

J

Considerando que na sua infraestrutura de conexão seja algo parecido com pelo menos esse exemplo simples:

public class ConnectionFactory {
    public Connection getConnection() {
        try {
            return DriverManager.getConnection(
                "jdbc:mysql://localhost/seubanco", "root", "");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

E na sua classe de negócio:

public List<Tipo> atenderRequisicaoXYZ() throws Exception {
    Connection connection = new ConnectionFactory().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

É 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

Então o problema pode ser em outro lugar que voce não tenha mostrado.

P

@javaflex Segue detalhes do código

Servlet

@WebServlet("/income")
public class IncomeServlet extends HttpServlet {
	private IncomeService incomeService = new IncomeService();

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
    
          //SETs da income.....

          incomeService.insert(income);
    }
}

Service

public class IncomeService {
	
	private Connection connection = new ConnectionDBFactory().getConnection();
	private IncomeDao incomeDao = new IncomeDao(connection);
	private PeriodDao periodDao = new PeriodDao(connection);

	public Income insert(Income income) throws Exception{
		try{
			
			Period period = periodDao.findByMonthAndYear(income.getPeriod().getMonth(), income.getPeriod().getYear());
			
			if(period == null){
				period = periodDao.insertObject(income.getPeriod());
			}
			
			income.setPeriod(period);
			income = incomeDao.insertObject(income);
			connection.commit();
			return income;			
			
		}catch (Exception e) {
			connection.rollback();
			throw new RuntimeException(e);
		}
	}

}

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

Tem várias formas. A tentativa mais próxima do que você está fazendo seria assim:

public class VisitorService {
	private Connection connection;
	private VisitorDao visitorDao;

	public VisitorService() {
		connection = new ConnectionDBFactory().getConnection();
		visitorDao = new VisitorDao(connection);
	}

	@Override
	public void finalize() throws Throwable {
	    	connection.Close();
	    	super.finalize(); //ver se é necessário
	}

	public List<Visitor> getVisitorsTodayWithoutExit() throws Exception{		
		List<Visitor> visitors = visitorDao.getVisitorsTodayWithoutExit();
		return visitors;
	}
}

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.

Outra opção é usar Filter: https://www.caelum.com.br/apostila-java-web/recursos-importantes-filtros/#10-1-reduzindo-o-acoplamento-com-filtros

Fora isso, algum framework que gerencie conexão.

Criado 18 de novembro de 2016
Ultima resposta 19 de nov. de 2016
Respostas 13
Participantes 5