107 votes

La réutilisation d'un PreparedStatement plusieurs fois

dans le cas de l'utilisation de PreparedStatement avec un seul lien commun, sans piscine, puis-je recréer une instance pour chaque dml/sql opération de maintenir la puissance de déclarations préparées à l'avance?

Je veux dire:

for (int i=0; i<1000; i++) {
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
    preparedStatement.close();
}

au lieu de:

PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i=0; i<1000; i++) {
    preparedStatement.clearParameters();
    preparedStatement.setObject(1, someValue);
    preparedStatement.executeQuery();
}
preparedStatement.close();

ma question se pose par le fait que j'ai envie de mettre ce code dans un environnement multithread, pouvez-vous me donner quelques conseils? merci

148voto

BalusC Points 498232

La deuxième manière est un peu plus efficace, mais d'une bien meilleure façon est de les exécuter en lots:

PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < 1000; i++) {
    preparedStatement.setObject(1, someValue);
    preparedStatement.addBatch();
}
preparedStatement.executeBatch();
preparedStatement.close(); // Do this in the finally block!

Vous êtes cependant dépendante sur le pilote JDBC de mise en œuvre de la façon dont de nombreux lots vous pouvez exécuter à la fois. Vous pouvez par exemple vous souhaitez exécuter tous les 100 lots:

PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < 1000; i++) {
    preparedStatement.setObject(1, someValue);
    preparedStatement.addBatch();
    if ((i + 1) % 100 == 0) {
        preparedStatement.executeBatch();
    }
}
preparedStatement.executeBatch();
preparedStatement.close(); // Do this in the finally block!

Comme pour le multithread environnements, vous n'avez pas besoin de s'inquiéter à ce sujet si vous acquérir et de fermer la connexion et l'état le plus rapidement possible la portée à l'intérieur de la même méthode de bloc selon la normale JDBC idiome. Voici un exemple de base:

public void executeBatch(/* ... */) throws SQLException { 
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        connection = database.getConnection();
        preparedStatement = connection.prepareStatement(SQL);
        // ...
    } finally {
        close(preparedStatement);
        close(connection);
    }
}

Mise à jour: selon les commentaires, en fonction de l'exigence fonctionnelle, vous auriez souvent, en effet, comme pour n'engagent que la transaction lorsque tous les lots sont finis, sinon il peut être imprévisible, qui sont celles de l'lots sont déjà insérées/mis à jour et qui n'est pas. La DB serait se salir ensuite. Voici comment vous pouvez le faire:

public void executeBatch(/* ... */) throws SQLException { 
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    try {
        connection = database.getConnection();
        connection.setAutoCommit(false);
        preparedStatement = connection.prepareStatement(SQL);
        // ...
        connection.commit();
    } catch (SQLException e) {
        connection.rollback();
        throw e;
    } finally {
        close(preparedStatement);
        close(connection);
    }
}

14voto

Thilo Points 108673

La boucle dans votre code est seulement un exemple simplifié, droit?

Il serait préférable de créer la PreparedStatement qu'une seule fois, et la ré-utiliser maintes et maintes fois dans la boucle.

Dans les situations où cela n'est pas possible (parce qu'il est compliqué le déroulement du programme, un peu trop), il est toujours avantageux d'utiliser un PreparedStatement, même si vous utilisez seulement une fois, parce que le côté serveur de l'œuvre (de l'analyse du SQL de mise en cache et le plan d'exécution), sera encore réduite.

Pour répondre à la situation que vous souhaitez re-utiliser le Java côté PreparedStatement, certains pilotes JDBC (comme Oracle) ont une fonction de mise en cache: Si vous créez un PreparedStatement pour les mêmes SQL sur la même connexion, il vous donnera la même (cache) de l'instance.

À propos de multi-threading: je ne pense pas que les connexions JDBC peuvent être partagés entre plusieurs threads (c'est à dire utilisé simultanément par plusieurs threads) de toute façon.Chaque thread doit obtenir son propre connexion de la piscine, de l'utiliser et de le retourner à la piscine à nouveau.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X