Querying with PreparedStatement and ResultSet
Parameterised queries, iterating result rows, and the 1-indexed column trap.
Why PreparedStatement?
PreparedStatement compiles the SQL template once and lets you set ? placeholder values before each execution. This is both faster (the database re-uses the query plan) and safer (prevents SQL injection).
String sql = "SELECT id, name, salary FROM employees WHERE dept = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, "Engineering"); // ? at position 1
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
double salary = rs.getDouble(3); // positional: column 3
System.out.printf("%d %-20s %.2f%n", id, name, salary);
}
ResultSet iteration
A freshly returned ResultSet is positioned before the first row — there is no current row yet. You must call rs.next() to advance. The pattern is always:
while (rs.next()) {
// now on a valid row
}
Reading values: use typed getters like getString, getInt, getDouble. You can address a column by its label name (rs.getString("name")) or by its 1-based position (rs.getString(1)). Position 1 is the *first* column, not zero.
Setter positioning
Likewise, ? placeholders in the SQL are numbered from 1:
ps.setString(1, value1); // first ?
ps.setInt(2, value2); // second ?
Attempting position 0 throws SQLException: parameter index out of range.