rspec/rules/S6905/java/rule.adoc
github-actions[bot] 9b269a17f8
Create rule S6905: SQL queries should retrieve only necessary fields (#3603)
Co-authored-by: Angelo Buono <angelo.buono@sonarsource.com>
Co-authored-by: Irina Batinic <117161143+irina-batinic-sonarsource@users.noreply.github.com>
2024-02-19 10:10:11 +01:00

73 lines
2.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

The _Java Database Connectivity (JDBC) API_ provides the `java.sql.Statement` interface that allows to represent an SQL statement and to execute queries with the database.
== Why is this an issue?
A common reason for a poorly performant query is because its processing more data than required.
Querying unnecessary data demands extra work on the server, adds network overhead, and consumes memory and CPU resources on the application server.
The effect is amplified when the query includes multiple _joins_.
The rule flags an issue when a `SELECT *` query is provided as an argument to methods in `java.sql.Connection` and `java.sql.Statement`.
=== What is the potential impact?
* _Performance_: the unnecessary extra data being processed brings overhead.
* _Sustainability_: the extra resources used have a negative impact on the environment.
== How to fix it
Make the `SELECT *` an explicit selection of the required fields.
=== Code examples
==== Noncompliant code example
[source,java,text,diff-id=1,diff-type=noncompliant]
----
public class OrderRepository {
public record OrderSummary(String name, String orderId, BigDecimal price) { }
public List<OrderSummary> queryOrderSummaries(Connection conn) {
String sql = "SELECT * " + // Noncompliant
"FROM Orders JOIN Customers ON Orders.customerId = Customers.id ";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
return convertResultToOrderSummaryList(rs);
}
}
----
==== Compliant solution
[source,java,text,diff-id=1,diff-type=compliant]
----
public class OrderRepository {
public record OrderSummary(String name, String orderId, BigDecimal price) { }
public List<OrderSummary> queryOrderSummaries(Connection conn) {
String sql = "SELECT Customers.name, Orders.id, Orders.price " + // Compliant
"FROM Orders JOIN Customers ON Orders.customerId = Customers.id ";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
return convertResultToOrderSummaryList(rs);
}
}
----
== Resources
=== Documentation
* https://docs.oracle.com/en/java/javase/21/docs/api/java.sql/java/sql/Statement.html[Oracle SDK - Statement]
* https://www.oreilly.com/library/view/high-performance-mysql/9780596101718/ch04.html[O'Reilly - High Performance MySQL - Query Performance Optimization]
=== Articles & blog posts
* https://www.geeksforgeeks.org/difference-between-execute-query-and-update-methods-in-java/[GeeksforGeeks - Difference Between Execute(), query() and Update() Methods in Java]