1. Overview
In this tutorial, we'll explore the differences between JDBC‘s Statement and PreparedStatement
2. JDBC API Interface
Both Statement and PreparedStatement can be used to execute SQL queries. These interfaces look very similar. However, they differ significantly from one another in features and performance:
- Statement – Used to execute string-based SQL queries
- PreparedStatement – Used to execute parameterized SQL queries
To be able to use Statement and PreparedStatement in our examples, we'll declare the h2 JDBC connector as a dependency in our pom.xml file:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
public class PersonEntity {
private int id;
private String name;
// standard setters and getters
}
Statement interface accepts strings as SQL queries. Thus, the code becomes less readable when we concatenate SQL
public void insert(PersonEntity personEntity) {
String query = "INSERT INTO persons(id, name) VALUES(" + personEntity.getId() + ", '"
+ personEntity.getName() + "')";
Statement statement = connection.createStatement();
statement.executeUpdate(query);
}
dao.update(new PersonEntity(1, "hacker' --"));
dao.insert(new PersonEntity(1, "O'Brien"))
public void insert(List<PersonEntity> personEntities) {
for (PersonEntity personEntity: personEntities) {
insert(personEntity);
}
}
Fourthly, the Statement interface is suitable for DDL queries like CREATE, ALTER, and :
public void createTables() {
String query = "create table if not exists PERSONS (ID INT, NAME VARCHAR(45))";
connection.createStatement().executeUpdate(query);
}
Statement interface can’t be used for storing and retrieving files and arrays.
Firstly, the PreparedStatement
public void insert(PersonEntity personEntity) {
String query = "INSERT INTO persons(id, name) VALUES( ?, ?)";
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, personEntity.getId());
preparedStatement.setString(2, personEntity.getName());
preparedStatement.executeUpdate();
}
@Test
void whenInsertAPersonWithQuoteInText_thenItNeverThrowsAnException() {
assertDoesNotThrow(() -> dao.insert(new PersonEntity(1, "O'Brien")));
}
@Test
void whenAHackerUpdateAPerson_thenItUpdatesTheTargetedPerson() throws SQLException {
dao.insert(Arrays.asList(new PersonEntity(1, "john"), new PersonEntity(2, "skeet")));
dao.update(new PersonEntity(1, "hacker' --"));
List<PersonEntity> result = dao.getAll();
assertEquals(Arrays.asList(
new PersonEntity(1, "hacker' --"),
new PersonEntity(2, "skeet")), result);
}
Thirdly, the PreparedStatement uses pre-compilation. As soon as the database gets a query, it will check the cache before pre-compiling the query. Consequently, if it is not cached, the database engine will save it for the next usage.
Moreover, this feature speeds up the communication between the database and the JVM through a non-SQL binary protocol. That is to say, there is less data in the packets, so the communication between the servers goes faster.
Fourthly, the PreparedStatement
public void insert(List<PersonEntity> personEntities) throws SQLException {
String query = "INSERT INTO persons(id, name) VALUES( ?, ?)";
PreparedStatement preparedStatement = connection.prepareStatement(query);
for (PersonEntity personEntity: personEntities) {
preparedStatement.setInt(1, personEntity.getId());
preparedStatement.setString(2, personEntity.getName());
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
}
PreparedStatement provides an easy way to store and retrieve files by using BLOB and CLOB data types. In the same vein, it helps to store lists by converting java.sql.Array to a SQL Array.
Lastly, the PreparedStatement implements methods like getMetadata() that contain information about the returned result.
In this tutorial, we presented the main differences between PreparedStatement and Statement. Both interfaces offer methods to execute SQL queries, but it is more suitable to use Statement for DDL queries and PreparedStatement for DML queries.
As usual, all the code examples are available over on GitHub.