2012-05-29 9 views
70

Cześć Zastanawiałem się, czy można wykonać coś takiego za pomocą JDBC, ponieważ obecnie zapewnia wyjątek, mimo że jest to możliwe w przeglądarce zapytań MySQL.Wiele zapytań wykonanych w java w pojedynczej instrukcji

"SELECT FROM * TABLE;INSERT INTO TABLE;" 

Choć zdaję sobie sprawę, że jest to możliwe z konieczności ciąg kwerendy SQL rozszczepiony oraz oświadczenie wykonywany dwa razy, ale zastanawiałem się, czy nie jest to podejście jeden raz za to.

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

umieścić w procedurze przechowywanej, zadzwonić do procedury przechowywanej. oznacza, że ​​nie musisz też ponownie wdrażać kodu, gdy chcesz wprowadzić zmianę. – Chris

+3

Istnieje właściwość, którą musisz ustawić w ciągu połączenia 'allowMultiQueries = true'. – Rahul

+0

prawdopodobny duplikat: Jak wykonywać kwerendy złożone sql w java? [1] [1]: http://stackoverflow.com/questions/6773393/how-to-execute-composite-sql-queries-in-java – prayagupd

Odpowiedz

100

Zastanawiałem się, czy możliwe jest, aby wykonać coś takiego przy użyciu JDBC.

"SELECT FROM * TABLE;INSERT INTO TABLE;" 

Tak, jest to możliwe. Są dwa sposoby, o ile wiem. Są

  1. Poprzez ustawienie właściwości połączenia z bazą danych, aby umożliwić wielu zapytań, oddzielone średnikiem domyślnie.
  2. Wywołanie procedury składowanej, która zwraca nieokreślone kursory.

Poniższe przykłady pokazują powyższe dwie możliwości.

Przykład 1 (Aby umożliwić wielu zapytań):

podczas wysyłania żądania połączenia, trzeba dołączyć właściwość połączenia allowMultiQueries=true do adresu URL bazy danych. Jest to dodatkowa właściwość połączenia z tymi, które już istnieją, np. autoReConnect=true itd. Akceptowane wartości dla właściwości allowMultiQueries to true, false, yes i no. Każda inna wartość jest odrzucana w czasie wykonywania z wartością SQLException.

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

ile taka instrukcja jest przekazywana, SQLException jest wyrzucane. Aby uzyskać wyniki wykonania kwerendy, należy użyć execute(String sql) lub jej innych wariantów.

boolean hasMoreResultSets = stmt.execute(multiQuerySqlString); 

iterację i proces rezultaty wymagają następujące czynności:

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 

Przykład 2: Kroki do naśladowania:

  1. Utwórz procedurę z jednym lub więcej select i DML zapytania.
  2. Zadzwoń do niego z Java za pomocą CallableStatement.
  3. Możesz przechwycić wiele wykonanych ResultSet s w procedurze.
    Nie można przechwycić wyników DML, ale można wydać kolejny numer select
    , aby dowiedzieć się, w jaki sposób wpływają na wiersze w tabeli.

stół próbki i procedura:

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) 

wywołanie procedury z 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 
+0

Niestety, to nie działa z wbudowaną wersją gry Derby. – user2428118

+0

@ user2428118: Powód? Jakiekolwiek zaobserwowane błędy? Czy sprawdziłeś, czy sterownik obsługuje tę funkcję? –

+0

Dodałem allowMultiQueries = true i działa dobrze :) – Hazim

0

Dlaczego nie próbujesz napisać do tego Stored Procedure?

Możesz pobrać Result Set w tym samym Stored Procedure można Insert, co chcesz.

Jedyną rzeczą, której nie można uzyskać nowo wstawionych wierszy w Result Set, jeśli Insert po Select.

21

Można użyć aktualizacji Batch ale zapytań musi być działanie (tj. Wstawianie, aktualizowanie i usuwanie) odpytuje

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(); 
+0

Nie można użyć tej metody dla zapytań "wywołanie sprocname (" abc ", 984)"? – sebnukem

7

podstawie moich badań, prawidłowa flaga jest "allowMultiQueries = true"

12

Wskazówka: jeśli masz więcej niż jedną conne Nieruchomość ction następnie rozdzielić je:

& 

aby dać Ci somthing jak:

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

Mam nadzieję, że to pomoże kogoś.

Pozdrawiam,

Glyn

0

Myślę, że to najprostszy sposób na wybór multy/aktualizacja/insert/delete. Możesz uruchomić tyle aktualizacji/wstawić/usunąć, ile chcesz po wyborze (musisz najpierw dokonać selekcji (w razie potrzeby manekina)) z executeUpdate (str) (wystarczy użyć nowego int (count1, count2, ...)) a jeśli potrzebujesz nowego wyboru, zamknij "oświadczenie" i "połączenie" i zrób nowe dla następnego wyboru. Jak np:

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

Mam nadzieję, że to pomaga

+1

Otwarcie połączenia DB jest bardzo kosztowne. Nie jest to dobra praktyka, która robi to za każdym razem. Podane wartości powinny dać liczbę trafień dla n liczby zapytań, co prowadzi do niskiej wydajności. –

Powiązane problemy