2024-02-22 10:38:39 +01:00
|
|
|
The `java.sql.PreparedStatement` represents a precompiled SQL statement that can be efficiently executed multiple times.
|
|
|
|
|
|
|
|
== Why is this an issue?
|
|
|
|
|
|
|
|
The `PreparedStatement` is frequently used in loops because it allows to conveniently set parameters.
|
|
|
|
A small optimization is possible by setting constant parameters outside the loop or hard-coding them in the query whenever possible.
|
|
|
|
|
|
|
|
=== What is the potential impact?
|
|
|
|
|
|
|
|
* _Performance_: the unnecessary calls to the setter methods bring overhead.
|
|
|
|
* _Sustainability_: the extra overhead has a negative impact on the environment.
|
|
|
|
|
|
|
|
== How to fix it
|
|
|
|
|
|
|
|
Place calls to setter methods that take a constant argument outside the loop.
|
|
|
|
|
|
|
|
=== Code examples
|
|
|
|
|
|
|
|
==== Noncompliant code example
|
|
|
|
|
|
|
|
[source,java,diff-id=1,diff-type=noncompliant]
|
|
|
|
----
|
|
|
|
public class DatabaseExample {
|
|
|
|
|
|
|
|
public record Order(String id, BigDecimal price) {}
|
|
|
|
|
|
|
|
public void updateTodayOrders(Connection connection, List<Order> orders) {
|
|
|
|
Date today = java.sql.Date.valueOf(LocalDate.now());
|
|
|
|
String insertQuery = "INSERT INTO Order (id, price, executionDate) VALUES (?, ?, ?)";
|
2024-06-26 12:18:18 +02:00
|
|
|
PreparedStatement preparedStatement = connection.prepareStatement(insertQuery);
|
2024-02-22 10:38:39 +01:00
|
|
|
|
|
|
|
for(Order order: orders) {
|
|
|
|
preparedStatement.setString(1, order.id());
|
|
|
|
preparedStatement.setString(2, order.price());
|
|
|
|
preparedStatement.setDate(3, today); // Noncompliant
|
|
|
|
preparedStatement.executeUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
|
|
|
|
|
|
|
==== Compliant solution
|
|
|
|
|
|
|
|
[source,java,diff-id=1,diff-type=compliant]
|
|
|
|
----
|
|
|
|
public class DatabaseExample {
|
|
|
|
|
|
|
|
public record Order(String id, BigDecimal price) {}
|
|
|
|
|
|
|
|
public void updateTodayOrders(Connection connection, List<Order> orders) {
|
|
|
|
Date today = java.sql.Date.valueOf(LocalDate.now());
|
|
|
|
String insertQuery = "INSERT INTO Order (id, price, executionDate) VALUES (?, ?, ?)";
|
2024-06-26 12:18:18 +02:00
|
|
|
PreparedStatement preparedStatement = connection.prepareStatement(insertQuery);
|
2024-02-22 10:38:39 +01:00
|
|
|
|
2024-06-26 12:18:18 +02:00
|
|
|
preparedStatement.setDate(3, today); // Compliant
|
2024-02-22 10:38:39 +01:00
|
|
|
for(Order order: orders) {
|
|
|
|
preparedStatement.setString(1, order.id());
|
|
|
|
preparedStatement.setString(2, order.price());
|
|
|
|
preparedStatement.executeUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
----
|
|
|
|
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://docs.oracle.com/en/java/javase/21/docs/api/java.sql/java/sql/PreparedStatement.html[Oracle SDK - PreparedStatement]
|
|
|
|
* https://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html[Oracle Tutorial - Using Prepared Statements]
|