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;
}
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.
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.
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.
Using a try-with-resources around all your JDBC resources makes your code more self-documenting as to your intentions.
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).
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 ()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With