Comment limiter le nombre de lignes renvoyées par Oracle au niveau de la source de données JDBC?

StackOverflow https://stackoverflow.com/questions/320299

  •  11-07-2019
  •  | 
  •  

Question

Existe-t-il un moyen de limiter les lignes renvoyées au niveau de la source de données Oracle dans une application Tomcat?

Il semble que maxRows n'est disponible que si vous le définissez dans la source de données dans le code Java. Mettre maxRows="2" sur la source de données ne s'applique pas.

Existe-t-il un autre moyen de limiter les lignes renvoyées? Sans changement de code?

Était-ce utile?

La solution

Ce n'est pas quelque chose qui est disponible au niveau de la configuration. Vous voudrez peut-être vérifier qu'il fait ce que vous voulez, de toute façon: voir le javadoc pour setMaxRows . Avec Oracle, il va toujours récupérer chaque ligne pour la requête, puis simplement supprimer celles qui se trouvent en dehors de la plage. Vous devez vraiment utiliser rownum pour que cela fonctionne bien avec Oracle et vous ne pouvez pas le faire non plus dans la configuration.

Autres conseils

La question est de savoir pourquoi vous souhaitez limiter le nombre de lignes renvoyées. Il pourrait y avoir plusieurs raisons de le faire. La première serait simplement de limiter les données renvoyées par la base de données. À mon avis, cela n'a aucun sens dans la plupart des cas, car si je souhaitais obtenir certaines données uniquement, j'utiliserais une déclaration différente ou ajouterais une condition de filtre ou quelque chose du genre. Par exemple. Si vous utilisez rownum d’Oracle, vous ne savez pas exactement quelles données se trouvent dans les lignes que vous récupérez et quelles données ne sont pas incluses, vous indiquez simplement à la base de données que vous voulez les lignes x à y.
La deuxième approche consiste à limiter l'utilisation de la mémoire et à augmenter les performances afin que le ResultSet que vous obtenez du pilote JDBC n'inclue pas toutes les données. Vous pouvez limiter le nombre de lignes détenues par le ResultSet à l'aide de Statement.setFetchSize () . Si vous déplacez le curseur dans le ResultSet au-delà du nombre de lignes extraites, le pilote JDBC extraira les données manquantes de la base de données. (Dans le cas d’Oracle, la base de données stockera les données dans un curseur de référence auquel le pilote JDBC a directement accès.)

  

* Attention: le code ci-dessous est fourni à titre d'exemple pur. Il n'a pas   été testé * Cela pourrait donc vous blesser, endommager votre ordinateur ou même vous frapper   en face.

Si vous souhaitez éviter de modifier vos requêtes SQL tout en conservant un code propre (ce qui signifie que votre code reste maintenable), vous pouvez concevoir la solution à l'aide de wrappers. En d’autres termes, en utilisant un petit ensemble de classes qui encapsulent les classes existantes, vous pouvez obtenir ce que vous voulez de manière transparente pour le reste de l’application, qui pensera toujours fonctionner avec de véritables sources de données, connexions et instructions.

1 - implémentez une classe StatementWrapper ou PreparedStatementWrapper, en fonction de ce que votre application utilise déjà. Ces classes sont des wrappers autour d'instances normales de Statement ou PreparedStatement. Elles sont simplement implémentées en utilisant l’instruction interne en tant que délégué qui effectue tout le travail, sauf s’il s’agit d’une instruction QUERY (méthode Statement.executeQuery ()). Ce n'est que dans cette situation précise que l'encapsuleur entoure la requête des deux chaînes suivantes: & "SELECT * FROM (&" Et & ";) WHERE ROWNUM & Lt; " + maxRowLimit. Pour le code d’encapsuleur de base, voyez ci-dessous l’apparence de DataSourceWrapper.

2 - écrivez un dernier wrapper: ConnectionWrapper qui enveloppe une connexion qui renvoie StatementWrapper dans createStatement () et PreparedStatementWrapper dans prepareStatement (). Ce sont les classes précédemment codées qui utilisent delegateConnection.createStatement () / prepareStatement () de ConnectionWrapper comme arguments de construction.

3 - répétez l'étape avec un DataSourceWrapper. Voici un exemple de code simple.

public class DataSourceWrapper implements DataSource
{
    private DataSource mDelegate;

    public DataSourceWrapper( DataSource delegate )
    {
        if( delegate == null ) { throw new NullPointerException( "Delegate cannot be null" );
        mDelegate = delegate;
    }

    public Connection getConnection(String username, String password)
    {
        return new ConnectionWrapper( mDelegate.getConnection( username, password ) );
    }

    public Connection getConnection()
    {
        ... <same as getConnection(String, String)> ...
    }
}

4 - Enfin, utilisez DataSourceWrapper en tant que source de données de votre application. Si vous utilisez JNDI (NamingContext), cette modification doit être simple.

Le codage de tout cela est rapide et très simple, surtout si vous utilisez un IDE intelligent comme Eclipse ou IntelliJ qui implémentera les méthodes de délégation automatiquement.

Si vous savez que vous n'utiliserez qu'une seule table, définissez une vue avec rownum dans l'instruction where pour limiter le nombre de lignes. De cette manière, le nombre de lignes est contrôlé dans la base de données et n'a pas besoin d'être spécifié dans le cadre d'une requête provenant d'une application cliente. Si vous souhaitez modifier le nombre de lignes renvoyées, redéfinissez la vue avant d'exécuter la requête.

Une méthode plus dynamique consisterait à développer une procédure, à lui transmettre un certain nombre de lignes et à lui faire renvoyer un ref_cursor à votre client. Cela aurait l'avantage d'éviter une analyse syntaxique difficile sur la base de données et d'augmenter les performances.

Ok, un changement de code devra être fait ensuite.

Le scénario limite l'utilisation d'un outil de génération de rapports ad hoc afin que l'utilisateur final ne récupère pas trop d'enregistrements et ne génère pas de rapport inutilisable.

Nous utilisons déjà la gestion des ressources Oracle basée sur les coûts.

scroll top