Ya estoy inscrito ¿Todavía no tienes acceso? Nuestros Planes
Ya estoy inscrito ¿Todavía no tienes acceso? Nuestros Planes
Solucionado (ver solución)
Solucionado
(ver solución)
5
respuestas

"AWT-EventQueue-0" java.lang.RuntimeException: java.sql.SQLException: You can't operate on a closed Connection

Al realizar el reto del del modulo 5.5, me salia un error de que no podía operar con un objeto cerrado, efectivamente puse un print en la operacion guardar para probar el objeto con, me arrojaba en consola que el objeto era nulo, por lo que me di cuenta que la conexión se cerraba apenas hacia la opcion de listar los elementos de la base de datos.

Encontré en el foro varias soluciones a este problema recurrente pero con otros nombres, espero les sirva

https://app.aluracursos.com/forum/topico-duda-problema-con-clase-dao-conexion-cerrada-y-buenas-practicas-209582

https://app.aluracursos.com/forum/topico-duda-cierre-de-conexion-para-otras-consultas-175209

5 respuestas

Yo tuve el mismo error, la solución se encuentra en la clase ProductoDAO, a los métodos que tenemos ahi tenemos que quitarle el CON en la sentencia TRY

public void guardar(Producto producto) {
        try (con) {
            final PreparedStatement statement = con.prepareStatement(
                    "INSERT INTO PRODUCTO (NOMBRE, DESCRIPCION, CANTIDAD) " + "VALUES (?, ?, ?)",
                    Statement.RETURN_GENERATED_KEYS);

            try (statement) {

                ejecutaRegistro(producto, statement);
                
            }
        }catch(SQLException e) {
            throw new RuntimeException(e);
        }
    }

Quedando de la siguiente manera

    public void guardar(Producto producto) {
        try{
            final PreparedStatement statement = con.prepareStatement(
                    "INSERT INTO PRODUCTO (NOMBRE, DESCRIPCION, CANTIDAD) " + "VALUES (?, ?, ?)",
                    Statement.RETURN_GENERATED_KEYS);

            try (statement) {

                ejecutaRegistro(producto, statement);
                
            }
        }catch(SQLException e) {
            throw new RuntimeException(e);
        }
    }

Asi mismo con todo los demás métodos, en los videos el instructor no lo explica pero en el codigo que nos da en el desafio como opinión del instructor se ve claro que ya no es necesario usarlo

solución!

Hola Jesus,

Sí, siempre debes asegurarte de que tu conexión a la base de datos esté abierta mientras estés realizando operaciones en ella. Gracias por compartir con nosotros =)

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.

@Ian Ubaldo Quistian Avila Si digamos que eso resuelve el problema de las demas operaciones pero el objeto "con" queda sin cerrarse y esto llevaría a una fuga de recursos que es una vulnerabilidad.

https://vulncat.fortify.com/es/detail?id=desc.controlflow.cpp.unreleased_resource_database

Por eso compartí los link anteriores y aca vi una alternativa similar a lo que estaba pensando https://app.aluracursos.com/forum/topico-duda-problema-con-clase-dao-conexion-cerrada-y-buenas-practicas-209582, donde cada vez que se llama una operacion se abre y se cierra la conexion de la siguiente forma:

llamada al metodo: new ProductoDAO().listar();

Instancia del metodo. public ProductoDAO() { con = new ConnectionFactory().recuperaConexion(); }

Estuve leyendo los post que recomiendas y estas son las conlusiones que saco

1.- La conexión si se cierra según palabras de Genesys Rondon ( en el siguiente enlace: https://app.aluracursos.com/forum/topico-duda-cierre-de-conexion-para-otras-consultas-175209) y dado que estamos usando try-with-resources la cual se encarga de cerrar la conexión automáticamente y no lo digo yo si no la misma documentación la cual la puedes leer acá: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html y dice explicitamente lo siguiente La try-with-resources statement garantiza que cada recurso se cierre al final de la declaración. Cualquier objeto que implemente java.lang.AutoCloseable, que incluye todos los objetos que implementen java.io.Closeable, puede usarse como recurso.

2.- Lo que hicieron mis compañero en la solución no le veo caso dado que ya esta implementado en el codigo *En nuestra clase ControlDeStockFrame se creo un objeto de la clase ProductoController con el nombre productoController el cual es instanciado en el constructor de esta clase *Como consecuencia de haber instanciado este objeto hicimos llamado del constructor de este mismo que se encuentra en la clase ProductoController, ahí mismo podrás notar que ya se encuentra implementando el siguiente código:

public ProductoController() {
        this.productoDAO = new ProductoDAO(new ConnectionFactory().recuperaConexion());
    }

Es importante entender esto, dado que lo que se esta haciendo es crear un nuevo objeto de la clase ProductoDOA, la clase ProductoDOA tiene un constructor que pide una conexión y lo que se puede ver en el código es que se inicializa este nuevo objeto con una nueva conexion, pero en este caso no con una conexión si no mas bien con un pool de conexión por la implementacion que se llevo acabo en la clase ConnectionFactory

public ProductoDAO(Connection con) {
        this.con = con;
    }

Volvamos a nuestra clase ControlDeStockFrame

Ahí podras notar que hacemos uso de nuestro objeto productoController en cada uno de los métodos, este es el usado en el metodo modificar

var filasModificadas = this.productoController.modificar(nombre, descripcion, id, cantidad);

El cual ya se a instanciado y ya ha creado una conexión por todo lo antes mencionado, en este ejemplo lo que hace es llamar al metodo modificar de la clase ProductoController la que a su vez hace un llamado al metodo modficar de la clase ProductoDOA y el cual tiene todo el codigo y por supuesto la implementación try-with-resources statement que a su vez se encarga de cerrar automáticamente la conexion.

Lo que veo en lo cual se están confundiendo es que ustedes piensan que la conexión se mantiene abierta porque ya no la volvemos a instanciar después de que se cerro, pero lo que se están olvidando es del pool de conexiones, el cual cito:

"Un pool de conexiones a base de datos es una forma de llevar un control de las mismas de modo que al desocupar una conexión, en lugar de cerrar la conexión la tengamos a la mano y se entregue al siguiente objeto que necesite una conexión.

Si bien esto puede sonar innecesario debe de recordar que crear una conexión a base de datos es una de las operaciones mas pesadas que puede efectuar y que las conexiones expiran automáticamente después de un tiempo sin uso, ambas cosas que pueden afectar el rendimiento o estabilidad de su aplicación.

Ahí es donde entra el pool de conexiones ya que este se encargara de reducir el numero de veces que necesite crear una nueva conexión y en caso que esta expire crea una nueva si es necesario." y pueden saber mas en la siguiente pagina: https://hashblogeando.wordpress.com/2016/04/25/pooling-de-conexiones-a-base-de-datos-con-c3p0-y-java/

A mi entender lo que se esta haciendo es que al cerrar la conexión lo que hace el pool es rehusarla y es ahí donde todos se estan confundiendo

¿En el contexto de usar un Pool de conexiones no es necesario usar try-with-resources en la conexión que recibe el ProductoDAO, dado que el fin de usar el c3po "pool de conexiones " es que la conexion se mantenga abierta para el próximo objeto que la necesite?, además el Pool crea nuevas conexiones en caso de que la conexión expire,¿porque nos e aclara este tema de forma adecuada siendo tan importante? , cerrar la conexión está bien o es algo que se encarga de gestionar el c3po?...