Java JDBC Statement
Execute SQL in Java with the Statement interface — when to use it vs. PreparedStatement.
Java JDBC Statement
A Statement sends a complete, fixed SQL string to the database. You create one from a Connection, hand it SQL, and get back either a ResultSet (for queries) or an update count (for changes). It is the simplest of the three statement types — and the one you should reach for least, because any variable data in the SQL must be concatenated in by hand, which is how SQL injection bugs are born.
Creating and executing
try (Connection conn = DriverManager.getConnection(url, user, pw);
Statement st = conn.createStatement()) {
// a query → ResultSet
try (ResultSet rs = st.executeQuery("SELECT count(*) FROM product")) {
rs.next();
System.out.println(rs.getInt(1));
}
// a change → update count
int rows = st.executeUpdate("UPDATE product SET active = true WHERE price > 0");
System.out.println(rows + " rows updated");
}Three execute methods
| Method | Use for | Returns |
|---|---|---|
executeQuery(sql) | SELECT | a ResultSet |
executeUpdate(sql) | INSERT / UPDATE / DELETE / DDL | int rows affected |
execute(sql) | unknown / multiple results | boolean (true if a ResultSet) |
Tuning the cursor and generated keys
When you create a statement you can choose how the resulting cursor behaves with createStatement(resultSetType, resultSetConcurrency) — for example TYPE_FORWARD_ONLY, CONCUR_READ_ONLY (the default and fastest). For inserts, Statement.RETURN_GENERATED_KEYS lets you read back an auto-generated primary key via getGeneratedKeys().
When NOT to use Statement
The moment any part of the SQL comes from a variable — a user name, an id, a search term — stop and use PreparedStatement instead. Concatenating values into a Statement string is unsafe: a value containing a quote can change the meaning of the command. The next chapter is dedicated to the safe alternative.
A worked example: the cursor constants and the injection trap
This program prints the ResultSet/Statement tuning constants you pass when creating a statement, then demonstrates concretely why string-built SQL is dangerous — by showing what a malicious value does to the command text.
What to take from the run:
- The cursor constants are plain
ints you pass tocreateStatement.TYPE_FORWARD_ONLY+CONCUR_READ_ONLYis the default and cheapest; you only ask for a scrollable or updatable cursor when you genuinely need it. Statement.RETURN_GENERATED_KEYSis the flag that lets anINSERTgive you the new auto-increment id back throughgetGeneratedKeys()— without it you cannot recover the database-assigned key.- The first concatenated query is harmless because
Acmehas no SQL metacharacters. That is exactly why string concatenation seems to work in testing — and then breaks in production on real-world input. - The second value contains a quote and a semicolon, so the single intended
SELECTbecomes aSELECTfollowed by aDROP TABLE. The data escaped its quotes and became executable SQL — the textbook definition of injection. - The fix is never "escape the quotes yourself." It is to stop building SQL from values at all and let
PreparedStatementsend the template and the data separately — the subject of the next chapter.
Practice
Your code builds a query by concatenating a web-form value directly into the SQL string after WHERE owner =. What is the correct fix?