Error closing Connection, Statement and ResultSet within try-catch-finally in Java, can not be resolved as variable

1

I still have problems to close my connections correctly, the error I have now is that the variables of Connection, Statement and ResultSet, says that I must create them locally, so what should I do?.

My code:

    String showTableSQL = "SELECT * FROM llamadas";
    try {
        Connection conn = conexion.getConnection();
        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery(showTableSQL);

        while (rs.next()) {
            // Obtenemos el modelo del JTable
            model = (DefaultTableModel) table.getModel();

            // Agregamos las filas al JTable
            model.addRow(new Object[]{
                            Integer.toString(rs.getInt(1)),
                            rs.getString(2),
                            rs.getString(3),
                            rs.getString(4),
                            rs.getString(5),
                            Integer.toString(rs.getInt(6)),
                            Double.toString(rs.getDouble(7))
                                });
                            }

    } catch (SQLException errorSQL) { errorSQL.printStackTrace(); }
        finally { // Cerramos las conexiones, en orden inverso a su apertura
            try { rs.close(); } catch (Exception errorRS) { errorRS.printStackTrace(); }
            try { st.close(); } catch (Exception errorST) { errorST.printStackTrace(); }
            try { conn.close(); } catch (Exception errorCONN) { errorCONN.printStackTrace(); }
        }

The error is in

  

rs, st and conn: can not resolve, create local variable

I hope you can help me solve this, I've been trying for 2 days. I'm still learning MySQL.

Any help is appreciated.

    
asked by Robert Gomez 26.11.2016 в 14:18
source

3 answers

4

Successfully close the instances of Connection , Statement , ResultSet and handle well all the errors that may result using the typical pattern of try-catch-finally is not easy. And if you succeed, the code is not elegant.

For example, even if you correct your problem immediately to move the definition of the variables outside the try , the code still has at least one design flaw.

Let's say that the code is corrected in this way (and by the way, reading the comments under the response of @Dev Joel, it is necessary to clarify that it is necessary to initialize the variables to some value as null . that, the Java compiler can not guarantee that the variables have some assigned value when they are used in the finally block, and that's why they complain, and in fact, this point is linked to the defect that I'm going to show) :

String showTableSQL = "SELECT * FROM llamadas";

// inicializar las variables sí es necesario aquí.
Connection conn = null;
Statement st = null;
ResultSet rs = null;

try {
    conn = conexion.getConnection(); // <-- ¿qué pasa si un error sucede aquí?
    st = conn.createStatement();
    rs = st.executeQuery(showTableSQL);

    // ...    
} catch (SQLException errorSQL) {
    errorSQL.printStackTrace();
}
finally { // Cerramos las conexiones, en orden inverso a su apertura
    try { rs.close(); } catch (Exception errorRS) { errorRS.printStackTrace(); }
    try { st.close(); } catch (Exception errorST) { errorST.printStackTrace(); }
    try { conn.close(); } catch (Exception errorCONN) { errorCONN.printStackTrace(); }
}

Now let's imagine that some error happens in this sentence:

conn = conexion.getConnection();

That causes that st and rs are with values null , and now, when the block finally is executed, both rs.close(); as st.close() are going to launch a NullPointerException that could be have avoided.

So the correct way to handle block finally is to check if the variables are at null before trying to close them:

finally { // Cerramos las conexiones, en orden inverso a su apertura
    try { if (rs != null) rs.close(); } catch (Exception errorRS) { errorRS.printStackTrace(); }
    try { if (st != null) st.close(); } catch (Exception errorST) { errorST.printStackTrace(); }
    try { if (conn != null) conn.close(); } catch (Exception errorCONN) { errorCONN.printStackTrace(); }
}

A better alternative

The above simply illustrates that it is easy to make mistakes with this type of code due to its complexity. And even if you manage to do it right, the complexity obscures the true purpose of the code.

For this reason, starting with Java 7, there is a better way to handle this type of situation, using try-with-resources . Using this technique, note how you can simplify your code and how clear it is:

String showTableSQL = "SELECT * FROM llamadas";

try (Connection conn = conexion.getConnection();
     Statement st = conn.createStatement();
     ResultSet rs = st.executeQuery(showTableSQL)) {

    // ...

} catch (SQLException e) {
    e.printStackTrace();
}

If you read the documentation , you'll see that this simplified code structure automatically handles the following aspects:

  • All .close() are automatically executed at the end of block try and in the reverse order of the opening of the different instances.
  • If an error occurs with one or more of the .close() , those exceptions do not replace the main exception, if any.
  • Related to the previous point, if more than one error occurs, either in the body of the try or with the .close() , e.printStackTrace() includes the information of all the errors automatically.
answered by 26.11.2016 / 19:37
source
2

The error is that you are declaring the variables rs st and conn within the block of the first try{}catch(){} and when you try to access it in try{}catch(){} of finally are no longer accessible as they are outside of the field.

  

The scope of a variable defines its scope of use, or what is the same, in which sections of code a variable will be available. Outside of this scope, a variable can not be accessed (it does not exist).

The scope of your three variables in your program is the first try{} catch(){} . To solve it declare the variables at the method level (before try{}catch(){} )

 public static void main(String[] args) {
    String showTableSQL = "SELECT * FROM llamadas";
    ResultSet rs=null;
    Statement st=null;
    Connection conn = null;
try {
      conn = conexion.getConnection();
      st = conn.createStatement();
      rs = st.executeQuery("");
      /* Demás código */
    }
    finally {
try { if (rs != null) rs.close(); } catch (Exception errorRS) { errorRS.printStackTrace(); }
try { if (st != null) st.close(); } catch (Exception errorST) { errorST.printStackTrace(); }
try { if (conn != null) conn.close(); } catch (Exception errorCONN) { errorCONN.printStackTrace(); }
}
    
answered by 26.11.2016 в 14:45
-2

A serious way that you lock everything in a try and catch more or less like that

Singleton Connection

public class DBConnection {
private static DBConnection instance = null;
private Connection connection;
protected DBConnection(){
    this.conectaPGSQL();
}

public Connection getConnection(){
    return this.connection;
}

public static DBConnection getInstance(){
    if(instance == null){
        System.out.println("Instancia nueva");
        instance = new DBConnection();
    }
    return instance;
}

private Connection conectaPGSQL(){
    try{

            this.connection = //aqui va el condigo de tu driver manager para la conexion
            if (this.connection != null) {
            } else {
                JOptionPane.showMessageDialog(null, "Falló al conectar la Base de datos","Connection Error", JOptionPane.ERROR_MESSAGE);
            }
            return this.connection;

    }catch(Exception e){
            JOptionPane.showMessageDialog(null, e.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
            e.printStackTrace();
            return null;
    }

}


}

Example

    String showTableSQL = "SELECT * FROM llamadas";
    DBConnection db = DBConnection.getInstance();
try {
    Connection conn = db.getConnection();
    Statement st = conn.createStatement();
    ResultSet rs = st.executeQuery(showTableSQL);

    while (rs.next()) {
        // Obtenemos el modelo del JTable
        model = (DefaultTableModel) table.getModel();

        // Agregamos las filas al JTable
        model.addRow(new Object[]{
                        Integer.toString(rs.getInt(1)),
                        rs.getString(2),
                        rs.getString(3),
                        rs.getString(4),
                        rs.getString(5),
                        Integer.toString(rs.getInt(6)),
                        Double.toString(rs.getDouble(7))
                            });
                        }

                        rs.close();
                        st.close();
} catch (Exception e) { e.printStackTrace(); }
    
answered by 26.11.2016 в 15:07