Solucionado (ver solución)
Solucionado
(ver solución)
1
respuesta

[Duda] SQLException - Cierre de la conexión

El profesor durante la explicacion menciona que debemos cerrar los recursos abiertos luedo de usarlos, por tal motivo usamos un try with resources cada que inicamos una conexion durante el desarrollo del ejercicio ProductosDAO, Sin embargo cuando ejecuto la plicación me arroja una SQLException que dice que no puedo trabajar con una conexion cerrada. Aunque ya pude solucionar el problema quitando el try with resources, me gustaria saber porque sucede esto, ya que se supone que cuando se ejecuta el try la conexion esta abierta y el statement se deberia enviar normalmente para ejecutar la accion deseada en la tabla asociada a dicha entidad en la base de datos.

Aqui comparto el codigo con el que tuve problemas

package com.alura.jdbc.dao;

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

import com.alura.jdbc.modelo.Producto;

public class ProductoDAO {
    
    final private Connection con;     // La conexion se deja como una constante para que la admita el try with resources
    
    public ProductoDAO(Connection con) {
        this.con = con;
    }
    
    public void guardarProducto(Producto producto) {
        try(con){            // aqui uso el try with resources
        	
        	final PreparedStatement statement = con.prepareStatement("INSERT INTO PRODUCTO (nombre, descripcion, cantidad, categoria_id) "
        			+ " VALUES(?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
        	
        	try(statement) {
        		statement.setString(1, producto.getNombre());
            	statement.setString(2, producto.getDescripcion());
            	statement.setInt(3, producto.getCantidad());
            	statement.setInt(4, producto.getCategoriaId());
            	
        		statement.execute();
            	
            	final ResultSet resultSet = statement.getGeneratedKeys();
            	
            	try(resultSet){
            		while(resultSet.next()) {
            			producto.setId(resultSet.getInt(1));
            			
                		System.out.println(String.format("Fue insertado el producto %s", producto));
                	}
            	}
        	}
        } catch (SQLException e) {   // Segun el trackTrace el problema ocurre porque se activa esta SQLException
        	throw new RuntimeException(e);
        }	
    }

    public List<Producto> listar() {
        
        try(con){            // aqui uso el try with resources
            final PreparedStatement statement = con.prepareStatement("SELECT ID, NOMBRE, DESCRIPCION, CANTIDAD FROM PRODUCTO");
            try(statement){
                statement.execute();
                final ResultSet resultSet = statement.getResultSet();
                try(resultSet){
                    List<Producto> fila = new ArrayList<>();
                    while (resultSet.next()) {
                        Producto producto= new Producto(resultSet.getInt("ID"), resultSet.getString("NOMBRE"), 
                                resultSet.getString("DESCRIPCION"),
                                resultSet.getInt("CANTIDAD"));
                        fila.add(producto);
                    }
                    return fila;
                }
            }
        }catch(SQLException e) {
            throw new RuntimeException(e);
        }
        
    }

    public int eliminar(Integer id) {
        
        try(con){            // aqui uso el try with resources
            final PreparedStatement statement = con.prepareStatement("DELETE FROM PRODUCTO WHERE ID = ?");
            try(statement){
                statement.setInt(1, id);
                statement.execute();
                int updateCount = statement.getUpdateCount();
                return updateCount;
            }
        }catch(SQLException e) {
            throw new RuntimeException(e);
        }
        
    }

    public int modificar(String nombre, String descripcion, Integer cantidad, Integer id) {

        try(con){            // aqui uso el try with resources
            final PreparedStatement statement = con.prepareStatement("UPDATE PRODUCTO SET NOMBRE = ?, DESCRIPCION = ?, CANTIDAD = ?  WHERE ID = ?");
            try(statement){
                statement.setString(1, nombre);
                statement.setString(1, descripcion);
                statement.setInt(1, cantidad);
                statement.setInt(1, id);
                statement.execute(); 
                int updateAcount = statement.getUpdateCount();
                return updateAcount;
            }
        }catch(SQLException e) {
            throw new RuntimeException(e);
        }
        
    }
}
1 respuesta
solución!

Hola Yoseph,

Sí, entiendo y es un detalle muy importante a tener en cuenta cuando trabajamos con bases de datos en Java.

El bloque try-with-resources se utiliza para asegurarnos de que los recursos se cierren automáticamente al finalizar el bloque, sin importar si se producen excepciones o no. En tu caso, estás utilizando try(con), donde con es tu objeto de conexión a la base de datos. Esto significa que al finalizar el bloque try, la conexión con se cerrará automáticamente.

El problema aquí es que estás utilizando la misma conexión con en varios métodos de tu clase ProductoDAO. Cuando llamas a uno de estos métodos, se abre un bloque try-with-resources y al finalizar, se cierra la conexión. Entonces, si después intentas llamar a otro método que también utiliza try(con), te encontrarás con que la conexión ya está cerrada, lo que provoca la SQLException que estás viendo.

Una posible solución sería mover el try-with-resources a un nivel superior, donde se llama a estos métodos, en lugar de tenerlo en cada método individual. De esta manera, la conexión se abrirá y cerrará una sola vez, en lugar de abrirse y cerrarse en cada método.

Aquí tienes un ejemplo de cómo podría verse esto:

try (Connection con = obtenerConexion()) {
    ProductoDAO productoDAO = new ProductoDAO(con);
    productoDAO.guardarProducto(producto);
    List<Producto> productos = productoDAO.listar();
    // etc...
} catch (SQLException e) {
    throw new RuntimeException(e);
}

En este ejemplo, obtenerConexion() sería un método que devuelve una nueva conexión a la base de datos. Este bloque try-with-resources asegura que la conexión se cierre automáticamente, incluso si se produce una excepción.

Recuerda que es importante cerrar siempre tus recursos, pero también necesitas asegurarte de que no se cierren antes de que hayas terminado de usarlos.

Espero haber ayudado y buenos estudios! Mucho éxito en todo lo que te propongas y si tienes alguna duda aquí estaremos para apoyarte.

¡Vamos juntos!

Si este post te ayudó, por favor, marca como solucionado ✓. Continúa con tus estudios