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

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

A aplicação sobe e roda uma vez. Se eu tentar atualizar a lista, aparece uma mensagem de erro de conexão fechada.

SEVERE: Servlet.service() for servlet [spring mvc] in context with path [/contas] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: java.sql.SQLException: Connection is closed.] with root cause

Copiei o mesmo código.

6 respostas

Oi Flavio,

Voce pode colar o codigo aqui?

Um abraco!

package br.com.caelum.contas.controller;

import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
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.dao.UsuarioDAO;
import br.com.caelum.contas.modelo.Conta;
import br.com.caelum.contas.modelo.Usuario;

@Controller
public class ContaController {

    private ContaDAO dao;

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

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

    @RequestMapping("/adicionaConta")
    public String adicionaConta(@Valid Conta conta, BindingResult result){

        if(result.hasErrors()){
            return "conta/formulario";
        }


        dao.adiciona(conta);

        return "conta/conta-inserida";
    }

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

    @RequestMapping("/removeConta")
    public String removeConta(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 pagaConta(long id, HttpServletResponse response){
        dao.paga(id);
        response.setStatus(200);
    }

    @RequestMapping("/loginForm")
    public String loginForm(){
        return "loginForm";
    }

    @RequestMapping("/efetuaLogin")
    public String efetuaLogin(Usuario usuario, HttpSession session){
        UsuarioDAO dao = new UsuarioDAO();
        if(dao.existeUsuario(usuario)){
            session.setAttribute("usuarioLogado", usuario);
            return "menu";
        }
        else{
            return "redirect:loginForm";
        }
    }

    @RequestMapping("/logout")
    public String logout(HttpSession session, HttpServletResponse response){
        session.invalidate();
        return "redirect:loginForm";
    }


}
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.Repository;

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

@Repository
public class ContaDAO {
    private Connection connection;

    @Autowired
    public ContaDAO(DataSource ds) {
        try {
            this.connection = ds.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;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc 
                        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
                        http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="br.com.caelum.contas" />
    <mvc:annotation-driven />
    <mvc:default-servlet-handler />
    <mvc:interceptors>
        <bean class="br.com.caelum.contas.interceptor.AutorizadorInterceptor" />
    </mvc:interceptors>

    <bean id="conversionService"
        class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="br.com.caelum.contas.StringToEnumConverterFactory" />
            </list>
        </property>
    </bean>

    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>    

    <bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
        <property name="url" value="jdbc:hsqldb:file:contas.db"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>

</beans>
solução!

Oi Flávio,

A conexão está sendo fechada. Veja no seu DAO que no fim de cada método você faz um connection.close(). Aí se você chama 2 métodos de um DAO na sequência, você tomará erro! Tira isso e seu código deve funcionar.

Mais pra frente, você verá que a abertura e fechamento de conexão deve acontecer em um filtro. Aí esse tipo de problema passa a sumir.

Entendeu?

Um abraço!

Oi Mauricio. E como eu faço um filtro para resolver esse problema? Não corre o risco de sobrecarregar o servidor se eu deixar as conexões abertas?

Corre o risco sim, Nilo.

Google por "Open Session in View", que você vai entender melhor o que estou dizendo!!

Você pode me ajudar a fazer esse filtro?