W3docs

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

MethodUse forReturns
executeQuery(sql)SELECTa ResultSet
executeUpdate(sql)INSERT / UPDATE / DELETE / DDLint rows affected
execute(sql)unknown / multiple resultsboolean (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.

java— editable, runs on the server

What to take from the run:

  • The cursor constants are plain ints you pass to createStatement. TYPE_FORWARD_ONLY + CONCUR_READ_ONLY is the default and cheapest; you only ask for a scrollable or updatable cursor when you genuinely need it.
  • Statement.RETURN_GENERATED_KEYS is the flag that lets an INSERT give you the new auto-increment id back through getGeneratedKeys() — without it you cannot recover the database-assigned key.
  • The first concatenated query is harmless because Acme has 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 SELECT becomes a SELECT followed by a DROP 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 PreparedStatement send the template and the data separately — the subject of the next chapter.

Practice

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?