Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Estou com dúvida no curso de Desenvolvendo aplicações Web com Spring MVC, no exercício do capítulo Injeção de dependências.

Aparentemente, após repetir exatamente o que foi feito na vídeo aula, várias partes do sistema pararam de funcionar corretamente. Acredito que porque ao se usar o mesmo DAO em todos os métodos no ContaController, como há alguns redirecionamentos, ao se chamar outro método do DAO, o último encontra a conexão fechada pelo método chamado anteriormente. Qual seria a correção usar commit() ao invés de close()? Onde seria o ponto correto para se fechar a conexão?

3 respostas

Pablo, pode conferir se o redirect está sendo feito do lado do cliente ou do servidor? Para isso você pode conferir qual a URI que fica lá em cima na barra do browser após acessar a funcionalidade: se for a URI original, o redirect foi no servidor, se a URI for a nova, o redirect aconteceu no cliente.

Está tudo como redirect. Dessa forma é do lado do cliente, correto?! De qualquer forma testei com redirect e foward e o comportamento é o mesmo. Segue o código abaixo e a msg de erro:

package br.com.caelum.contas.controller;

import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;

import br.com.caelum.contas.dao.ContaDAO;
import br.com.caelum.contas.modelo.Conta;

@Controller
public class ContaController {
    private ContaDAO dao;

    @Autowired
    public ContaController(ContaDAO dao) {
        this.dao = dao;
    }

    @RequestMapping("/form")
    public String execute() {
        return "conta/formulario";
    }

    @RequestMapping("/adicionaConta")
    public String adiciona(@Valid Conta conta, BindingResult result) {
        if (result.hasErrors()) {
            return "conta/formulario";
        }

        System.out.println("Adicionando conta " + conta.getDescricao());

        dao.adiciona(conta);

        return "conta/contaAdicionada";
    }

    @RequestMapping("/listaContas")
    public String lista(Model mv) {
        List<Conta> contas = dao.lista();

        // ModelAndView mv = new ModelAndView("conta/listaContas");
        // mv.addObject("contas", contas);
        mv.addAttribute("contas", contas);

        return "conta/listaContas";
    }

    @RequestMapping("/removeConta")
    public String remove(Conta conta) {
        dao.remove(conta);

        return "redirect:listaContas";
    }

    @RequestMapping("/mostraConta")
    public String mostra(Long id, Model model) {
        model.addAttribute("conta", dao.buscaPorId(id));
        return "conta/mostra";
    }

    @RequestMapping("/alteraConta")
    public String altera(Conta conta) {
        dao.altera(conta);
        return "redirect:listaContas";
    }

    @RequestMapping("/pagaConta")
    public void finaliza(Long id, HttpServletResponse response) {
        dao.paga(id);
        response.setStatus(200);
    }
}
package br.com.caelum.contas.dao;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import br.com.caelum.contas.modelo.Conta;
import br.com.caelum.contas.modelo.TipoDaConta;

@Component
public class ContaDAO {
    private Connection connection;

    @Autowired
    public ContaDAO(DataSource dataSource) {
        try {
            //this.connection = new ConnectionFactory().getConnection();
            this.connection = dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void adiciona(Conta conta) {
        String sql = "insert into contas (descricao, paga, valor, tipo) values (?,?,?,?)";
        PreparedStatement stmt;
        try {
            stmt = connection.prepareStatement(sql);
            stmt.setString(1, conta.getDescricao());
            stmt.setBoolean(2, conta.isPaga());
            stmt.setDouble(3, conta.getValor());
            stmt.setString(4, conta.getTipo().name());
            stmt.execute();
            connection.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

    }

    public void remove(Conta conta) {

        if (conta.getId() == null) {
            throw new IllegalStateException("Id da conta naoo deve ser nula.");
        }

        String sql = "delete from contas where id = ?";
        PreparedStatement stmt;
        try {
            stmt = connection.prepareStatement(sql);
            stmt.setLong(1, conta.getId());
            stmt.execute();

            connection.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void altera(Conta conta) {
        String sql = "update contas set descricao = ?, paga = ?, dataPagamento = ?, tipo = ?, valor = ? where id = ?";
        PreparedStatement stmt;
        try {
            stmt = connection.prepareStatement(sql);
            stmt.setString(1, conta.getDescricao());
            stmt.setBoolean(2, conta.isPaga());
            stmt.setDate(3, conta.getDataPagamento() != null ? new Date(conta
                    .getDataPagamento().getTimeInMillis()) : null);
            stmt.setString(4, conta.getTipo().name());
            stmt.setDouble(5, conta.getValor());
            stmt.setLong(6, conta.getId());
            stmt.execute();

            connection.close();

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public List<Conta> lista() {
        try {
            List<Conta> contas = new ArrayList<Conta>();
            PreparedStatement stmt = this.connection
                    .prepareStatement("select * from contas");

            ResultSet rs = stmt.executeQuery();

            while (rs.next()) {
                // adiciona a conta na lista
                contas.add(populaConta(rs));
            }

            rs.close();
            stmt.close();
            connection.close();

            return contas;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public Conta buscaPorId(Long id) {


        if (id == null) {
            throw new IllegalStateException("Id da conta nao deve ser nula.");
        }

        try {
            PreparedStatement stmt = this.connection
                    .prepareStatement("select * from contas where id = ?");
            stmt.setLong(1, id);
            ResultSet rs = stmt.executeQuery();

            if (rs.next()) {
                connection.close();
                return populaConta(rs);
            }

            rs.close();
            stmt.close();


            connection.close();
            return null;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void paga(Long id) {

        if (id == null) {
            throw new IllegalStateException("Id da conta nao deve ser nula.");
        }

        String sql = "update contas set paga = ?, dataPagamento = ? where id = ?";
        PreparedStatement stmt;
        try {
            stmt = connection.prepareStatement(sql);
            stmt.setBoolean(1, true);
            stmt.setDate(2, new Date(Calendar.getInstance().getTimeInMillis()));
            stmt.setLong(3, id);
            stmt.execute();

            connection.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private Conta populaConta(ResultSet rs) throws SQLException {
        Conta conta = new Conta();

        conta.setId(rs.getLong("id"));
        conta.setDescricao(rs.getString("descricao"));
        conta.setPaga(rs.getBoolean("paga"));
        conta.setValor(rs.getDouble("valor"));

        Date data = rs.getDate("dataPagamento");
        if (data != null) {
            Calendar dataPagamento = Calendar.getInstance();
            dataPagamento.setTime(data);
            conta.setDataPagamento(dataPagamento);
        }

        conta.setTipo(Enum.valueOf(TipoDaConta.class, rs.getString("tipo")));

        return conta;
    }
}
HTTP Status 500 - Request processing failed; nested exception is java.lang.RuntimeException: java.sql.SQLException: Connection is closed.

--------------------------------------------------------------------------------

type Exception report

message Request processing failed; nested exception is java.lang.RuntimeException: java.sql.SQLException: Connection is closed.

description The server encountered an internal error that prevented it from fulfilling this request.

exception 

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.RuntimeException: java.sql.SQLException: Connection is closed.
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:681)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:574)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)


root cause 

java.lang.RuntimeException: java.sql.SQLException: Connection is closed.
    br.com.caelum.contas.dao.ContaDAO.remove(ContaDAO.java:68)
    br.com.caelum.contas.controller.ContaController.remove(ContaController.java:57)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:601)
    org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:574)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)


root cause 

java.sql.SQLException: Connection is closed.
    org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.checkOpen(PoolingDataSource.java:185)
    org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:312)
    br.com.caelum.contas.dao.ContaDAO.remove(ContaDAO.java:61)
    br.com.caelum.contas.controller.ContaController.remove(ContaController.java:57)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:601)
    org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:574)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)


note The full stack trace of the root cause is available in the Apache Tomcat/7.0.33 logs.


--------------------------------------------------------------------------------

Apache Tomcat/7.0.33
solução!

Oi Pablo,

Você está certo. Tire o connection.close() dos métodos do seu DAO.

Depois, a ideia é que você crie um Interceptor, que abre a conexão, e só depois de todo o processamento da action, ele fecha a conexão.

Faz sentido?