Mehrere Abfragen in Java in einer einzigen Anweisung ausgeführt

100

Hallo, ich habe mich gefragt, ob es möglich ist, so etwas mit JDBC auszuführen, da es derzeit eine Ausnahme darstellt, obwohl dies im MySQL-Abfragebrowser möglich ist.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Ich weiß zwar, dass es möglich ist, die SQL-Abfragezeichenfolge zu teilen und die Anweisung zweimal auszuführen, aber ich habe mich gefragt, ob es dafür einen einmaligen Ansatz gibt.

    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);
MilindaD
quelle
1
Rufen Sie die gespeicherte Prozedur auf. bedeutet, dass Sie Ihren Code auch nicht erneut bereitstellen müssen, wenn Sie eine Änderung vornehmen möchten.
Chris
4
Es gibt eine Eigenschaft, die Sie in der Verbindungszeichenfolge festlegen müssen allowMultiQueries=true.
Rahul
wahrscheinliches Duplikat: Wie führe ich zusammengesetzte SQL-Abfragen in Java aus? [1] [1]: stackoverflow.com/questions/6773393/…
prayagupd
1
Hallo Rahul, für dieses Projekt verwende ich ein einfaches altes Verbindungsobjekt und weißt du, wo ich "allowMultiQueries = true" setzen soll? Habe den Verbindungsobjektcode in die Frage
eingefügt

Antworten:

139

Ich habe mich gefragt, ob es möglich ist, so etwas mit JDBC auszuführen.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Ja, es ist möglich. Soweit ich weiß, gibt es zwei Möglichkeiten. Sie sind

  1. Durch Festlegen der Datenbankverbindungseigenschaft, um mehrere Abfragen zuzulassen, die standardmäßig durch ein Semikolon getrennt sind.
  2. Durch Aufrufen einer gespeicherten Prozedur, die implizite Cursor zurückgibt.

Die folgenden Beispiele zeigen die beiden oben genannten Möglichkeiten.

Beispiel 1 : (Um mehrere Abfragen zuzulassen):

Beim Senden einer Verbindungsanforderung müssen Sie eine Verbindungseigenschaft allowMultiQueries=truean die Datenbank-URL anhängen . Dies ist eine zusätzliche Verbindungseigenschaft zu denen , wenn bereits vorhanden einige, wie autoReConnect=true, etc .. Die zulässigen Werte für allowMultiQueriesImmobilien sind true, false, yes, und no. Jeder andere Wert wird zur Laufzeit mit einem abgelehnt SQLException.

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

Wenn eine solche Anweisung nicht übergeben wird, wird eine SQLExceptionausgelöst.

Sie müssen execute( String sql )oder seine anderen Varianten verwenden, um Ergebnisse der Abfrageausführung abzurufen.

boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );

Um die Ergebnisse zu durchlaufen und zu verarbeiten, benötigen Sie die folgenden Schritte:

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

Beispiel 2 : Folgende Schritte:

  1. Erstellen Sie eine Prozedur mit einem oder mehreren select, und DMLAbfragen.
  2. Nennen Sie es von Java mit CallableStatement.
  3. Sie können mehrere ResultSets erfassen, die in der Prozedur ausgeführt werden.
    DML-Ergebnisse können nicht erfasst werden, können jedoch andere ausgeben, select
    um festzustellen, wie die Zeilen in der Tabelle betroffen sind.

Beispieltabelle und Vorgehensweise :

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)

Aufrufprozedur von 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
Ravinder Reddy
quelle
Leider funktioniert dies nicht mit der eingebetteten Version von Derby.
user2428118
@ user2428118: Grund? Irgendwelche Fehler beobachtet? Haben Sie überprüft, ob der Treiber diese Funktion unterstützt?
Ravinder Reddy
Ich habe allowMultiQueries = true hinzugefügt und funktioniert gut :)
Hazim
Vielen Dank, dass Sie @RavinderReddy
Siva R
34

Sie können die Stapelaktualisierung verwenden, Abfragen müssen jedoch Aktionsabfragen (dh Einfügen, Aktualisieren und Löschen) sein

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();
Himanshu Mohta
quelle
1
Sie können diesen Ansatz nicht für Abfragen zum Aufrufen von Sprocname ('abc', 984) verwenden?
sebnukem
18

Hinweis: Wenn Sie mehr als eine Verbindungseigenschaft haben, trennen Sie diese durch:

&

Um Ihnen etwas zu geben wie:

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

Ich hoffe das hilft jemandem.

Grüße,

Glyn

Glyn
quelle
11

Basierend auf meinen Tests lautet das korrekte Flag "allowMultiQueries = true".

muye
quelle
2

Warum versuchst du nicht, eine Stored Proceduredafür zu schreiben ?

Sie können das Result Setrausholen und im selben können Stored ProcedureSie, Insertwas Sie wollen.

Die einzige Sache ist, dass Sie möglicherweise nicht die neu eingefügten Zeilen in der erhalten, Result Setwenn Sie Insertnach dem Select.

JHS
quelle
1
Sie haben nicht immer die Berechtigung, eine gespeicherte Prozedur zu schreiben. Zum Beispiel ist es eine Client-Datenbank, aus der Sie nur auswählen dürfen.
Pedram Bashiri
2

Ich denke, dies ist der einfachste Weg für die Auswahl / Aktualisierung / Einfügung / Löschung von Multys. Sie können nach der Auswahl mit executeUpdate (str) so viele Aktualisierungen / Einfügungen / Löschvorgänge ausführen, wie Sie möchten (Sie müssen zuerst eine Auswahl treffen (ggf. einen Dummy)) (verwenden Sie einfach new int (count1, count2, ...)). und wenn Sie eine neue Auswahl benötigen, schließen Sie 'Anweisung' und 'Verbindung' und machen Sie neue für die nächste Auswahl. Wie Beispiel:

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);
    }

Ich hoffe, es hilft

Alexandros Topalidis
quelle
1
Das Öffnen einer DB-Verbindung ist sehr kostspielig. Das ist nicht immer eine gute Übung. Das, was Sie angegeben haben, sollte n DB-Treffer für n Abfragen verursachen, was zu einer schlechten Leistung führt.
Arun Kumar Mudraboyina