Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java prepared statement in try-with-resources not working [duplicate]

Yesterday multiple people on Stack recommended using try-with-resources. I am doing this for all my database operations now. Today I wanted to change Statement to PreparedStatement to make the queries more secure. But when I try to use a prepared statement in try-with-resources I keep getting errors like 'identifier expected' or ';' or ')'.

What am I doing wrong? Or isnt this possible? This is my code:

    try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
        PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
        stmt.setInt(1, user);
        ResultSet rs = stmt.executeQuery()) {

        // if no record found
        if(!rs.isBeforeFirst()) {
           return false;
        }
        // if record found
        else {
            return true;
        }

    } catch (SQLException e) {
        // log error but dont do anything, maybe later
        String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
        return false;

    }
like image 557
Dylan Avatar asked Jul 24 '14 11:07

Dylan


People also ask

Can I use same prepared statement multiple times?

Once a PreparedStatement is prepared, it can be reused after execution. You reuse a PreparedStatement by setting new values for the parameters and then execute it again.

Can we write try-with-resources without catch and finally?

Yes, It is possible to have a try block without a catch block by using a final block. As we know, a final block will always execute even there is an exception occurred in a try block, except System. exit() it will execute always.

Do we need to close connection in try-with-resources?

Whenever, we instantiate and use certain objects/resources we should close them explicitly else there is a chance of Resource leak. The resources we declare in the try block should extend the java. lang. AutoCloseable class.

Why is it important to open JDBC connections using the try-with-resources try ){ }) syntax?

Using a try-with-resources around all your JDBC resources makes your code more self-documenting as to your intentions.


3 Answers

A try-with-resource statement is used to declare (Autoclosable) resources. Connection, PreparedStatement and ResultSet are Autoclosable, so that's fine.

But stmt.setInt(1, user) is NOT a resource, but a simple statement. You cannot have simple statements (that are no resource declarations) within a try-with-resource statement!

Solution: Create multiple try-with-resource statements!

try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
    executeStatement(conn);
} catch (SQLException e) {
    // log error but dont do anything, maybe later
    String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
    return false;
}

private void executeStatement(Connection con) throws SQLException {
    try (PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id=? LIMIT 1")) {
        stmt.setInt(1, user);
        try (ResultSet rs = stmt.executeQuery()) {
            // process result
        }
    }
}

(Please note that technically it is not required to put the execution of the SQL statement into a separate method as I did. It also works if both, opening the connection and creating the PreparedStatement are within the same try-with-resource statement. I just consider it good practice to separate connection management stuff from the rest of the code).

like image 126
isnot2bad Avatar answered Oct 05 '22 22:10

isnot2bad


try this code:

try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
     PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");

        stmt.setInt(1, user);
        ResultSet rs = pstmt.executeQuery())

        // if no record found
        if(!rs.isBeforeFirst()) {
           return false;
        }
        // if record found
        else {
            return true;
        }

    } catch (SQLException e) {
        // log error but dont do anything, maybe later
        String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
        return false;

    }

note that here, resource is your Connection and you have to use it in the try block ()

like image 21
Pat Avatar answered Oct 06 '22 00:10

Pat


Move

stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()

...within the try{ /*HERE*/ }

This is because stmt is the resource being created try (/*HERE*/) {} to be used try{ /*HERE*/ }

Try-with-resources

try (/*Create resources in here such as conn and stmt*/)
{
  //Use the resources created above such as stmt
}

The point being that everything created in the resource creation block implements AutoClosable and when the try block is exited, close() is called on them all. In your code stmt.setInt(1, user); is not an AutoCloseable resource, hence the problem.

like image 21
Ross Drew Avatar answered Oct 05 '22 22:10

Ross Drew