Plusieurs requêtes exécutées en java dans une seule instruction


100

Salut, je me demandais s'il est possible d'exécuter quelque chose comme ça en utilisant JDBC car il fournit actuellement une exception même si c'est possible dans le navigateur de requêtes MySQL.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Bien que je réalise qu'il est possible de diviser la chaîne de requête SQL et d'exécuter l'instruction deux fois, je me demandais s'il existe une approche unique pour cela.

    String url = "jdbc:mysql://localhost:3306/";
    String dbName = "databaseinjection";
    String driver = "com.mysql.jdbc.Driver";
    String sqlUsername = "root"; 
    String sqlPassword = "abc";

    Class.forName(driver).newInstance();

    connection = DriverManager.getConnection(url+dbName, sqlUsername, sqlPassword);

1
mis dans une procédure stockée, appelez la procédure stockée. signifie également que vous n'avez pas à redéployer votre code lorsque vous souhaitez effectuer une modification.
Chris

4
Il y a une propriété que vous devez définir dans la chaîne de connexion allowMultiQueries=true.
Rahul

duplication probable: Comment exécuter des requêtes sql composites en java? [1] [1]: stackoverflow.com/questions/6773393/…
priagupd

1
Salut Rahul, pour ce projet, j'utilise un ancien objet de connexion et savez-vous où je dois définir "allowMultiQueries = true". Ont ajouté le code de l'objet de connexion dans la question
MilindaD

Réponses:


140

Je me demandais s'il était possible d'exécuter quelque chose comme ça en utilisant JDBC.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Oui c'est possible. Pour autant que je sache, il y a deux façons. Elles sont

  1. En définissant la propriété de connexion à la base de données pour autoriser plusieurs requêtes, séparées par un point-virgule par défaut.
  2. En appelant une procédure stockée qui renvoie des curseurs implicites.

Les exemples suivants illustrent les deux possibilités ci-dessus.

Exemple 1 : (Pour autoriser plusieurs requêtes):

Lors de l'envoi d'une demande de connexion, vous devez ajouter une propriété de connexion allowMultiQueries=trueà l'URL de la base de données. C'est une propriété de connexion supplémentaire à ceux si existe déjà certains, comme autoReConnect=true, etc .. Les valeurs acceptables pour la allowMultiQueriespropriété sont true, false, yeset no. Toute autre valeur est rejetée lors de l'exécution avec un SQLException.

String dbUrl = "jdbc:mysql:///test?allowMultiQueries=true";  

À moins qu'une telle instruction ne soit passée, un SQLExceptionest lancé.

Vous devez utiliser execute( String sql )ou ses autres variantes pour récupérer les résultats de l'exécution de la requête.

boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );

Pour parcourir et traiter les résultats, vous devez suivre les étapes suivantes:

READING_QUERY_RESULTS: // label  
    while ( hasMoreResultSets || stmt.getUpdateCount() != -1 ) {  
        if ( hasMoreResultSets ) {  
            Resultset rs = stmt.getResultSet();
            // handle your rs here
        } // if has rs
        else { // if ddl/dml/...
            int queryResult = stmt.getUpdateCount();  
            if ( queryResult == -1 ) { // no more queries processed  
                break READING_QUERY_RESULTS;  
            } // no more queries processed  
            // handle success, failure, generated keys, etc here
        } // if ddl/dml/...

        // check to continue in the loop  
        hasMoreResultSets = stmt.getMoreResults();  
    } // while results

Exemple 2 : étapes à suivre:

  1. Créez une procédure avec une ou plusieurs requêtes selectet DML.
  2. Appelez-le depuis Java en utilisant CallableStatement .
  3. Vous pouvez capturer plusieurs ResultSets exécutés dans la procédure.
    Les résultats DML ne peuvent pas être capturés mais peuvent en émettre un autre select
    pour déterminer comment les lignes sont affectées dans le tableau.

Exemple de tableau et procédure :

mysql> create table tbl_mq( i int not null auto_increment, name varchar(10), primary key (i) );
Query OK, 0 rows affected (0.16 sec)

mysql> delimiter //
mysql> create procedure multi_query()
    -> begin
    ->  select count(*) as name_count from tbl_mq;
    ->  insert into tbl_mq( names ) values ( 'ravi' );
    ->  select last_insert_id();
    ->  select * from tbl_mq;
    -> end;
    -> //
Query OK, 0 rows affected (0.02 sec)
mysql> delimiter ;
mysql> call multi_query();
+------------+
| name_count |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)

+------------------+
| last_insert_id() |
+------------------+
|                3 |
+------------------+
1 row in set (0.00 sec)

+---+------+
| i | name |
+---+------+
| 1 | ravi |
+---+------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Procédure d'appel depuis Java :

CallableStatement cstmt = con.prepareCall( "call multi_query()" );  
boolean hasMoreResultSets = cstmt.execute();  
READING_QUERY_RESULTS:  
    while ( hasMoreResultSets ) {  
        Resultset rs = stmt.getResultSet();
        // handle your rs here
    } // while has more rs

Malheureusement, cela ne fonctionne pas avec la version intégrée de Derby.
user2428118

@ user2428118: Raison? Des erreurs ont-elles été observées? Avez-vous vérifié si Driver prend en charge cette fonctionnalité?
Ravinder Reddy

J'ai ajouté allowMultiQueries = true et fonctionne bien :)
Hazim

Merci @RavinderReddy
Siva R

34

Vous pouvez utiliser la mise à jour par lots, mais les requêtes doivent être des requêtes d'action (c'est-à-dire insérer, mettre à jour et supprimer)

Statement s = c.createStatement();
String s1 = "update emp set name='abc' where salary=984";
String s2 = "insert into emp values ('Osama',1420)";  
s.addBatch(s1);
s.addBatch(s2);     
s.executeBatch();

1
Vous ne pouvez pas utiliser cette approche pour les requêtes "call sprocname ('abc', 984)"?
sebnukem

18

Conseil: si vous disposez de plusieurs propriétés de connexion, séparez-les par:

&

Pour vous donner quelque chose comme:

url="jdbc:mysql://localhost/glyndwr?autoReconnect=true&allowMultiQueries=true"

J'espère que ça aidera quelqu'un.

Cordialement,

Glyn


11

D'après mes tests, l'indicateur correct est "allowMultiQueries = true"


2

Pourquoi n'essayez-vous pas d'écrire un Stored Procedurepour cela?

Vous pouvez Result Setsortir et dans le même Stored Procedurevous pouvez Insertce que vous voulez.

La seule chose est que vous n'obtiendrez peut-être pas les lignes nouvellement insérées dans le Result Setsi vous Insertaprès le Select.


1
Vous n'êtes pas toujours autorisé à écrire une procédure stockée. Par exemple, c'est la base de données d'un client que vous êtes uniquement autorisé à sélectionner.
pedram bashiri

2

Je pense que c'est le moyen le plus simple de sélectionner / mettre à jour / insérer / supprimer plusieurs fois. Vous pouvez exécuter autant de mise à jour / d'insertion / de suppression que vous le souhaitez après la sélection (vous devez d'abord effectuer une sélection (un mannequin si nécessaire)) avec executeUpdate (str) (utilisez simplement new int (count1, count2, ...)) et si vous avez besoin d'une nouvelle sélection, fermez «instruction» et «connexion» et faites-en une nouvelle pour la prochaine sélection. Comme exemple:

String str1 = "select * from users";
String str9 = "INSERT INTO `port`(device_id, potition, port_type, di_p_pt) VALUE ('"+value1+"', '"+value2+"', '"+value3+"', '"+value4+"')";
String str2 = "Select port_id from port where device_id = '"+value1+"' and potition = '"+value2+"' and port_type = '"+value3+"' ";
try{  
    Class.forName("com.mysql.jdbc.Driver").newInstance();
    theConnection=(Connection) DriverManager.getConnection(dbURL,dbuser,dbpassword);  
    theStatement = theConnection.prepareStatement(str1);
    ResultSet theResult = theStatement.executeQuery();
    int count8 = theStatement.executeUpdate(str9);
    theStatement.close();
    theConnection.close();
    theConnection=DriverManager.getConnection(dbURL,dbuser,dbpassword);
    theStatement = theConnection.prepareStatement(str2);
    theResult = theStatement.executeQuery();

    ArrayList<Port> portList = new ArrayList<Port>();
    while (theResult.next()) {
        Port port = new Port();
        port.setPort_id(theResult.getInt("port_id"));

        portList.add(port);
    }

J'espère que ça aide


1
L'ouverture d'une connexion DB est très coûteuse. Ce n'est pas une bonne pratique de faire ça à chaque fois. Le que vous avez donné devrait faire n nombre de hits DB pour n nombre de requêtes, ce qui conduit à de mauvaises performances.
Arun Kumar Mudraboyina
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.