web-dev-qa-db-fra.com

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

Bonjour, je me demandais s'il était possible d'exécuter quelque chose comme ceci 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 me rende compte qu'il est possible de scinder la chaîne de requête SQL et d'exécuter l'instruction deux fois, mais je me demandais s'il existait 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);
81
MilindaD

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

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Oui c'est possible. Il y a deux façons, à ma connaissance. 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. Ceci est une propriété de connexion supplémentaire à ceux qui existent déjà, comme autoReConnect=true, etc. Les valeurs acceptables pour la propriété allowMultiQueries sont true, false, yes et no. Toute autre valeur est rejetée à l'exécution avec une variable SQLException

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

À moins qu'une telle instruction ne soit transmise, une SQLException est lancée.

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 select et DML.
  2. Appelez-le depuis Java en utilisant CallableStatement.
  3. Vous pouvez capturer plusieurs ResultSets exécutés dans une procédure.
    Les résultats DML ne peuvent pas être capturés mais peuvent générer une autre select
    pour trouver comment les lignes sont affectées dans la table. 

Exemple de table et de 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 à partir de 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
122
Ravinder Reddy

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();
25
Himanshu Mohta

Astuce: Si vous avez 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

14
Glyn

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

10
muye

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

Vous pouvez obtenir le Result Set et dans le même Stored Procedure vous pouvez Insert ce que vous voulez.

La seule chose à faire est que vous pourriez ne pas obtenir les nouvelles lignes insérées dans Result Set si vous Insert après la Select.

2
JHS

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 mises à jour/insérer/supprimer que vous le souhaitez après la sélection (vous devez d'abord sélectionner (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 'statement' et 'connection' et faites new pour next select. 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