What is the correct way to close connections and statements?

1

I am developing my first application as a univ project. using MySQL with JAVA, I am realizing that there are methods and routines that do not close the connections and the statements although I give them their respective orders to do it, something I must do in a correct way so that this does not happen, that they suggest ?

WARNING: THIS CODE THAT IS SHOWN HERE CONTAINS ERRORS OF              INSTRUCTIONS, YOU CAN TAKE IT AS AN EXAMPLE TO KNOW              HOW TO CREATE A LOGIN AND HOW TO MAKE DIFFERENT OPERATIONS              WITH A TABLE OF USERS BUT THE GENERA CONNECTION CLASS              CONNECTIONS OF MORE AND DO NOT CLOSE READ WELL THE FULL POST              NOT TO FALL IN THE SAME ERROR THAT I DO.

This is the class I use to connect.

package metodos;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

public class Conexion {

private static final String DB = "sil";
private static final String DBuser = "root";
private static final String DBpwd = "****";
private static final String DBurl = "jdbc:mysql://localhost:3306/" + DB;

Connection Conector;


public Conexion() {

    try {
        Class.forName("com.mysql.jdbc.Driver");
        Conector = DriverManager.getConnection(DBurl, DBuser, DBpwd);

    } catch (ClassNotFoundException classNotFoundException) {
        JOptionPane.showMessageDialog(null, "Error con el driver JDBC");
    } catch (SQLException exception) {
        try {
            JOptionPane.showMessageDialog(null, "Error en la conexion");
            Conector.close();
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

public Connection getConexion() {
    return Conector;
}

/**
 * ¿ES NECESARIO ESTE METODO?
 * Este metodo cierra la conexion, para su uso
 * el manejo de recursos del sistema.
 */

/*public void cierraConexion() {
    try {
        Conector.close();
    } catch (Exception exception) {
        // TODO: handle exception
        System.out.println("Error cerrando la conexion");
    }

    }//Cierre del constructor*/

}//Fin de la clase Conexion

And this class uses the connection and generates connections in excess.

package metodos;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

public class OperacionesUsuarios {

Conexion Conecta = new Conexion();
Connection Conector;

public Object[][] AccedeUsuario(String login, String clave) {

    Conector = Conecta.getConexion();

    int registros = 0;
    int usu_id;

    try {
        String Query = "SELECT count(1) as cont" + " FROM usuarios";
        Statement St = Conector.createStatement();
        /*
        PreparedStatement pstm = Conn.prepareStatement(Query);
        ResultSet Rs = pstm.executeQuery();
         */
        try (ResultSet Rs = St.executeQuery(Query)) {
            /*
            PreparedStatement pstm = Conn.prepareStatement(Query);
            ResultSet Rs = pstm.executeQuery();
             */
            Rs.next();
            registros = Rs.getInt("cont");
            Rs.close();
        }
    } catch (SQLException sqle) {
        JOptionPane.showMessageDialog(null, "Error en la consulta MySQL");
        Logger.getLogger(OperacionesLicorerias.class.getName()).log(Level.SEVERE, null, sqle);
    }

    Object[][] data = new Object[registros][3];

    if (login.length() != 0 && clave.length() != 0) {

        String usu_login;
        String usu_password;

        try {
            String Query = "SELECT * FROM sil.usuarios WHERE login = '"
                    + login + "' AND clave = '" + clave + "'";
            Statement St = Conector.createStatement();
            /*  PreparedStatement pstm = Conn.prepareStatement(Query);
            try (ResultSet Rs = pstm.executeQuery()) {
             */
            try (ResultSet Rs = St.executeQuery(Query)) {
                int i = 0;
                while (Rs.next()) {
                    usu_id = Rs.getInt("idUsuarios");
                    usu_login = Rs.getString("login");
                    usu_password = Rs.getString("clave");
                    data[i][0] = usu_id;
                    data[i][1] = usu_login;
                    data[i][2] = usu_password;
                    i++;

                }
            }
        } catch (SQLException sqle) {
            JOptionPane.showMessageDialog(null, "Error en la consulta MySQL");
            Logger.getLogger(OperacionesLicorerias.class.getName()).log(Level.SEVERE, null, sqle);
        } finally {
            try {
                if (Conector != null) {
                    Conector.close();
                }
            } catch (SQLException sqle) {
                JOptionPane.showMessageDialog(null, "Error al cerrar la conexion");
                Logger.getLogger(OperacionesLicorerias.class.getName()).log(Level.SEVERE, null, sqle);
            }
        }
    }
    return data;
}

public void RegistrandoUsuario(String nombreUsuarios, String login, String clave) {

    Conector = Conecta.getConexion();

    try {
        String Query = "INSERT INTO 'sil'.'usuarios' ('nombreUsuarios',"
                + " 'login', 'clave') VALUES ('" + nombreUsuarios + "', '"
                + login + "', '" + clave + "');";
        try (Statement St = Conector.createStatement()) {
            St.executeUpdate(Query);
            JOptionPane.showMessageDialog(null, "Datos ingresados correctamente!");
            St.close();
            Conector.close();
        }
    } catch (SQLException SQLe) {
        JOptionPane.showMessageDialog(null, "Error en la consulta");
    }
    /*finally {
        if (Conector != null) {
            try {
                Conector.close();
            } catch (SQLException sqle) {
                JOptionPane.showMessageDialog(null, "Error al cerrar la conexion");
                Logger.getLogger(OperacionesLicorerias.class.getName()).log(Level.SEVERE, null, sqle);
            }
        }
    }*/
}

public ResultSet BuscaUsuario(String login) {

    Conector = Conecta.getConexion();

    String Query = "SELECT * FROM sil.usuarios where login = ?";
    Statement St = null;
    ResultSet Rs = null;
    PreparedStatement Pst = null;

    try {

        Pst = Conector.prepareStatement(Query);
        Pst.setString(1, login);
        Rs = Pst.executeQuery();
        while (Rs.next()) {

            JOptionPane.showMessageDialog(null, " | ID: " + Rs.getString("idUsuarios")
                    + " | Login: " + Rs.getString("login")
                    + " | Nombre: " + Rs.getString("nombreUsuarios"));
            St.close();
            Rs.close();
        }*/
    } catch (SQLException SQLe) {
        JOptionPane.showMessageDialog(null, "Error en la consulta");
        Logger.getLogger(OperacionesLicorerias.class.getName()).log(Level.SEVERE, null, SQLe);
    }
    return Rs;
}

public void BorraUsuario(String login) {

    Conector = Conecta.getConexion();

    try {
        String Query = "DELETE FROM usuarios WHERE 'login'='" + login + "';";
        Statement St = Conector.createStatement();
        St.executeUpdate(Query);
        JOptionPane.showMessageDialog(null, "Registro borrado con exito!");
        St.close();
    } catch (SQLException ex) {
        JOptionPane.showMessageDialog(null, "Error en la actualizacion de datos");
    } finally {
        if (Conector != null) {
            try {
                Conector.close();
            } catch (SQLException sqle) {
                JOptionPane.showMessageDialog(null, "Error al cerrar la conexion");
                Logger.getLogger(OperacionesLicorerias.class.getName()).log(Level.SEVERE, null, sqle);
                 }
             }
         }
     }
}

Last night I was able to solve the problem, as you can see in my code, apparently I am building an object or instantiating a class, which is already running the connection, and I also created a Connection type object to which I tell it to execute the method .getConnection, modify the code and remove the getConnection () method from my Conexion class, added the connection type to my Conexion method and that's where the shots went.

To realize where my error was, I had to comment on the instructions where there were connection methods, step by step testing the project and discard what was causing me connections that did not close, and I could determine that the problem was in my Conexion class.

If there is any information that someone wants to ask me would be perfect, as you can see I am learning on my own and I still need to handle many topics.

    
asked by Adrian 29.07.2016 в 21:06
source

4 answers

4

Your biggest problem is that the connection attribute Connection Conector (whose name should be lowercase) is designed as an attribute of the class when it should be local to the method where the database operations are performed. As good practices:

  • ALWAYS the connection to the database must be closed, either by using Connection#close manually or by try-with-resources .
  • Opening a physical connection to the database is a costly operation in terms of I / O, independent of the RDBMS engine (MySQL, Postgres, SQL Server, Oracle, DB2, etc). It is best to use a pool of connections, even if it is 1 connection, so that he maintains the connection or connections to live data and improves the performance of your application.
  • ALWAYS the connection to the database must be closed, it does not matter if you open the connection manually or if it comes from a pool of connections (it is always highlighted).
  • The database connection object, that is, the instance of Connection , must be initialized in a local scope, that is, it must be declared as a local variable in a method, so that the opening can be controlled and closing the connection to the database.
  • Any working framework with database on JDBC must comply with the good practices mentioned previously, otherwise, in the long run, it will generate problems.

That said, your problem has two solution options:

  • You remove the attribute Connection conector from class Conexion and move it as a local variable in each method, where you can make sure to close the connection when all operations are finished.
  • Maintain the attribute Connection conector in class Conexion but do not initialize it there, but receive it as a parameter in the constructor, so that clients of class Conexion will always have to open a database connection to use the instance of Conexion and then, when the operations are finished, they can close it properly.

Whichever option you use to manage connections, your code should look like this:

//uso de try-with-resources
//disponible desde Java 7, llamará automáticamente
//al método close de la o las instancias que se
//declaren en este bloque
try (Connection conector = ...) //iniciar la conexion a bd
{
    //operaciones con la conexion a bd
    try (PreparedStatement pstmt = conector.prepareStatement("SELECT ... ")) {
        pstmt.setParameter(1, ...);
        try (ResultSet rs = pstmt.executeQuery()) {
            //...
        }
    }
} catch (SQLException e) {
    //siempre se deben manejar las excepciones
    //por lo menos registra la excepción en la salida del programa
    System.out.println("Error en las operaciones a base de datos.");
    e.printStackTrace(System.out);
    //si te lo preguntas, sí, existen mejores opciones
    //pero esta es la más básica para tus primeros pasos
}

Example of a bit more real code of use of Connection and operations against the database:

//elementos necesarios en el método
//este normalmente es un atributo de la clase
Logger logger = ...;
//este debería ser un parámetro para el método
int id = ...;

public MiClase get(int id) {
    //valor a retornar
    MiClase miClase = new MiClase();
    miClase.setId(id);
    try (Connection conector = ...) //iniciar la conexion a bd
    {
        //aquí inician las operaciones con transaccionabilidad
        try {
            //lectura de la tabla "maestro"
            try (PreparedStatement pstmt = conector.prepareStatement("SELECT col1, col2 FROM maestro WHERE id = ? ")) {
                pstmt.setParameter(1, id);
                try (ResultSet rs = pstmt.executeQuery()) {
                    //sabemos que solo puede traer un resultado
                    if (rs.next()) {
                        miClase.setCol1(rs.getString("col1"));
                        miClase.setCol2(rs.getString("col2"));
                    }
                }
            }
            List<MiClase2> listaMiClase2 = new ArrayList<>();
            //lectura de la tabla "detalle"
            //Ojo! se utiliza el mismo objeto de conexion creado
            //al comienzo del método
            try (PreparedStatement pstmt = conector.prepareStatement("SELECT id, col1, col2 FROM detalle WHERE maestroId = ? ")) {
                pstmt.setParameter(1, id);
                try (ResultSet rs = pstmt.executeQuery()) {
                    //sabemos que puede traer uno o más resultados
                    while (rs.next()) {
                        MiClase2 miClase2 = new MiClase2();
                        miClase2.setId(rs.getInt("id"));
                        miClase2.setCol1(rs.getString("col1"));
                        miClase2.setCol2(rs.getString("col2"));
                        listaMiClase2.add(miClase2);
                    }
                }
            }
            miClase.setListaMiClase2(listaMiClase2);
        } catch (Exception e) {
            //por lo menos loguear el error
            logger.error("Error en las operaciones.", e);
            //y se ejecuta un rollback de las operaciones
            conector.rollback();
        }
    } catch (SQLException e) {
        //siempre se deben manejar las excepciones
        //por lo menos registra la excepción en la salida del programa
        System.out.println("Error en las operaciones a base de datos.");
        e.printStackTrace(System.out);
        //si te lo preguntas, sí, existen mejores opciones
        //pero esta es la más básica para tus primeros pasos
    }
    return miClase;
}

Obviously, this becomes a code wall. To avoid this type of spaguetti code, you can perform code refactorings or use a framework that saves this work. It should be noted that this framework, behind the scenes, should execute a structure similar to the one that appears here, otherwise that framework will bring performance problems in the application.

    
answered by 07.08.2016 / 19:01
source
0

The advisable thing would be that you created a method of closing connection, in which you only use your object.close (); And you call it once you finish doing the operations in the database.

Good luck!

    
answered by 12.08.2016 в 18:02
0

For the management of DB resources, what I did was to create a method that closes the connections in the class that contains my connection parameters and connection method.

The method has been left this way.

public void cierraConexion() {
    try {
        Conector.close();
    } catch (SQLException sqle) {
        JOptionPane.showMessageDialog(null, "Error al cerrar conexion", "Error", JOptionPane.ERROR_MESSAGE);
        Logger.getLogger(ConexionDAO.class.getName()).log(Level.SEVERE, null, sqle);
    }
}

This method applies when only when I want to close a connection that has been made, but if I want to close queries and connections, then I apply another method in the DAO class of what is being handled in question, for example, I have a class called usersDAO, what contains are the methods of operations that have to do with users (login, search, register, modify or delete) and at the end of the class a method that does what is required and has been left this way:

/**
 * Metodo CerrarConsultas: Este metodo permite cerrar consultas y conexion sí existen.
 */

public void cierraConsultas() {
    try {
        if (Rs != null) {
            Rs.close();
        }
        if (St != null) {
            St.close();
        }
        if (Conector != null) {
            Conector.close();
        }
    } catch (SQLException sqle) {
        JOptionPane.showMessageDialog(null, "Error cerrando la conexion!", "Error", JOptionPane.ERROR_MESSAGE);
        Logger.getLogger(LicoreriasDAO.class.getName()).log(Level.SEVERE, null, sqle);
    }
}

I would like to know your suggestions, I am new to programming, I have always liked it and I have been working hard to make things work for me but I need a bit of guidance.

Attentive to your comments Luiggi Mendoza . And waiting for you to mark my answer as positive, I say goodbye

    
answered by 12.08.2016 в 15:47
0

For the creation of a successful connection it would be like this: A method where you establish the connection in the following way:

public Connection establecerDB() {
    try{
        Class.forName("com.mysql.jdbc.Driver");
        String user = "root";
        String url = "jdbc:mysql://localhost:3306/grupoautofinprueba";
        String password = "";
        con = DriverManager.getConnection(url, user, password);
    }catch(ClassNotFoundException ex){
        JOptionPane.showMessageDialog(null,"Driver no encontrado");
    }catch(SQLException ex){
        JOptionPane.showMessageDialog(null,"Fallo al recibir base de datos");
    }catch(Exception ex){
        JOptionPane.showMessageDialog(null, "No hay resultado");
    }finally{
        return con;
    }
}

Then we created a closing method:

public void getClose() {
    try{
        con.close();
    }catch(SQLException ex){

    }
}

To be able to call it you should only do the following here is where I create a prepared statement that is the following way the example is about adding:

public boolean insertarProg_prod(Object _O) {
    try {
        confProg_prod objTemp = (confProg_prod) _O;
        PreparedStatement Agregar;
        Agregar = singleton.getConex().prepareStatement("Insert into prog_prod(dtInicio,dtFin,Departamento,Tarea,est_Tarea,strClave)values(?,?,?,?,?,?)");
        Agregar.setString(1, objTemp.getDtInicio());
        Agregar.setString(2, objTemp.getDtFin());
        Agregar.setInt(3, objTemp.getIdDepartamento());
        Agregar.setInt(4, objTemp.getIdTarea());
        Agregar.setInt(5, objTemp.getIdest_Tarea());
        Agregar.setString(6, objTemp.getStrClave());
        Agregar.execute();
        Agregar.close();
        singleton.getClose();
        JOptionPane.showMessageDialog(null, "Registro guardado");
        return true;
    } catch (SQLException e) {
        System.out.println(e.getErrorCode());
        System.out.println(e.getSQLState());
        System.out.println(e.getMessage());
        return false;
    }
}
    
answered by 15.08.2016 в 20:44