Arrêtez vos requêtes Oracle dans vos applications Java

Les formulaires de recherches multi-critères sont souvent une épine dans le pied des applications interactives. Je suis adepte de la solution brutale qui consiste à monter un cluster Hadoop et un formulaire avec une seul champ. Vous voyez de quoi je parle ?

Si vous n’avez pas 250 000 euros pour commencer ou l’ambition d’acheter un « BDA » [NDLR Oracle Big Data Appliance], cet article est peut-être pour vous ! Il présente un exemple d’utilisation de la méthode java.sql.ResultSet.setQueryTimeout pour arrêtez une requête qui n’a pas répondue au bout de X secondes depuis un formulaire multi-critères. Il revient sur l’affichage de « trop de données » aussi…
Vous comprendrez par vous-même ! Voici un exemple, dans un programme Java, d’une requête qui devrait prendre un peu de temps et, juste avant, le positionnement d’un délai de 10 secondes dans ce même programme pour vous assurer d’avoir une réponse dans les temps… ou pas de réponse :

cat StatementTimeout.java
import oracle.jdbc.pool.OracleDataSource;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class StatementTimeout {
public static void main(String[] args)
throws SQLException {
OracleDataSource ods = new OracleDataSource();
String url = "jdbc:oracle:thin:@pink:1521/WHITE";
ods.setURL(url);
ods.setUser("demo");
ods.setPassword("demo");

Connection conn = ods.getConnection();
Statement stmt = conn.createStatement();
stmt.setQueryTimeout(10);
String query = "select count(*) " +
" from all_objects a, " +
" all_objects b, " +
" all_objects c";
ResultSet rset = stmt.executeQuery(query);
while (rset.next())
System.out.println(rset.getInt(1));
rset.close();
stmt.close();
conn.close();
}
}

Le résultat parle de lui-même ! il ne reste plus au développeur malin qu’à tracer l’exception de manière élégante et renvoyer un conseil avisé pour encourager l’utilisateur de l’application à lancer sa requête en arrière plan ou à préciser des critères :

export CLASSPATH=.:$ORACLE_HOME/jdbc/lib/ojdbc6.jar
javac StatementTimeout.java
java StatementTimeout

Exception in thread "main" java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current operation

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:193)
at oracle.jdbc.driver.T4CStatement.executeForDescribe(T4CStatement.java:873)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1167)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1281)
at oracle.jdbc.driver.OracleStatement.executeQuery(OracleStatement.java:1491)
at oracle.jdbc.driver.OracleStatementWrapper.executeQuery(OracleStatementWrapper.java:406)
at StatementTimeout.main(StatementTimeout.java:23)

Bien sûr, dans l’idéal, il faudrait coder un écran qui oblige à saisir des critères pertinents et lancer des requêtes relativement optimisées mais c’est un premier pas de géant.

Si vous êtes DBA et que l’application n’est pas codées sur ce principe, il est peut-être possible de positionner un paramètre au niveau des pools de connexion JDBC. Il s’agit, dans le cas de weblogic, du paramètre « Timeout Statement ». Par ailleurs, vous pouvez aussi déclencher une erreur depuis la base de données. Lisez cet article sur le blog de Pythian qui met en oeuvre un timeout à l’aide de resource manager.

Dans le même style, les applications limitent généralement le nombre de résultats retournés par une recherche, par exemple à 150, estimant qu’un utilisateur ne s’amusera pas à regarder le détail de plus de 150 lignes retournées et l’encourageant à exécuter des requêtes plus précises ou à lancer l’opération en arrière plan. Si vous mettez en avant ce type d’approche, pourquoi compter le nombre de lignes retournées par la requête au préalable ? Ramenez 151 lignes et s’il y en a effectivement 151, c’est que la requête ramène plus de 150 lignes, non ? Ca évite d’exécuter 2 requêtes pour répondre à une question que personne ne pose. Si vous tenez à donner une indication, utilisez une clause « SAMPLE » dans la requête de comptage.

3 réflexions sur “Arrêtez vos requêtes Oracle dans vos applications Java”

  1. Merci pour ta réponse ArKZoYD.
    Dans mon cas c’est un peu plus compliqué. Techniquement je suis sur MySQL déjà, mais c’est surtout que les requêtes sont appelées à partir de JSP; elles-mêmes appelées par le client lourd. Je testerai le statement.cancel(), si ça fonctionne on peut adapter son architecture après.
    Bonne continuation !

  2. Bonjour et merci pour cet article.

    Une question sur le même sujet, mais d’un point de vue un peu différent.
    Comment l’utilisateur pourrait lui-même décider que la requête met trop de temps et annuler cette dernière de sa propre initiative ? (En cliquant sur un bouton annuler par exemple).
    Je ne connais pas d’instruction de type « KILL » qui soit standard SQL.

    Merci !

Les commentaires sont fermés.