Nhiều truy vấn được thực thi trong java trong một câu lệnh


100

Xin chào Tôi đã tự hỏi liệu có thể thực thi một cái gì đó như thế này bằng cách sử dụng JDBC vì nó hiện cung cấp một ngoại lệ mặc dù nó có thể trong trình duyệt truy vấn MySQL.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Mặc dù tôi nhận ra rằng có thể xảy ra việc phân tách chuỗi truy vấn SQL và câu lệnh được thực thi hai lần nhưng tôi tự hỏi liệu có cách tiếp cận một lần cho việc này hay không.

    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
đưa vào một thủ tục được lưu trữ, gọi thủ tục đã lưu trữ. có nghĩa là bạn cũng không phải triển khai lại mã của mình khi bạn muốn thực hiện thay đổi.
Chris

4
Có một thuộc tính bạn phải đặt trong chuỗi kết nối allowMultiQueries=true.
Rahul

có thể trùng lặp: Làm thế nào để thực hiện các truy vấn sql tổng hợp trong java? [1] [1]: stackoverflow.com/questions/6773393/…
Prayagupd

1
Xin chào Rahul, đối với dự án này, tôi đang sử dụng một đối tượng kết nối cũ thuần túy và bạn có biết nơi tôi nên đặt "allowMultiQueries = true" không. Đã thêm mã đối tượng kết nối trong câu hỏi
MilindaD

Câu trả lời:


139

Tôi đã tự hỏi liệu có thể thực thi một cái gì đó như thế này bằng cách sử dụng JDBC.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Có nó là có thể. Có hai cách, theo như tôi biết. họ đang

  1. Bằng cách đặt thuộc tính kết nối cơ sở dữ liệu để cho phép nhiều truy vấn, được phân tách bằng dấu chấm phẩy theo mặc định.
  2. Bằng cách gọi một thủ tục được lưu trữ trả về các con trỏ ngầm.

Các ví dụ sau chứng minh hai khả năng trên

Ví dụ 1 : (Để cho phép nhiều truy vấn):

Trong khi gửi yêu cầu kết nối, bạn cần nối thuộc tính kết nối allowMultiQueries=truevào url cơ sở dữ liệu. Đây là thêm thuộc tính kết nối với những người nếu đã tồn tại một số người, như autoReConnect=true, vv .. giá trị chấp nhận được đối với allowMultiQueriestài sản là true, false, yes, và no. Bất kỳ giá trị nào khác đều bị từ chối trong thời gian chạy bằng SQLException.

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

Trừ khi hướng dẫn như vậy được thông qua, an SQLExceptionsẽ được ném.

Bạn phải sử dụng execute( String sql )hoặc các biến thể khác của nó để lấy kết quả thực thi truy vấn.

boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );

Để lặp lại và xử lý kết quả, bạn yêu cầu các bước sau:

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

Ví dụ 2 : Các bước thực hiện:

  1. Tạo một thủ tục với một hoặc nhiều selectDMLcác truy vấn.
  2. Gọi nó từ java bằng cách sử dụng CallableStatement.
  3. Bạn có thể chụp nhiều ResultSets được thực thi trong thủ tục.
    Không thể thu select
    thập kết quả DML nhưng có thể đưa ra kết quả khác để tìm cách các hàng bị ảnh hưởng trong bảng.

Bảng mẫu và quy trình :

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)

Thủ tục cuộc gọi từ 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

Thật không may, điều này không hoạt động với phiên bản nhúng của Derby.
user2428118

@ user2428118: Lý do? Bất kỳ lỗi quan sát thấy? Bạn đã kiểm tra xem Driver có hỗ trợ tính năng này không?
Ravinder Reddy

tôi đã thêm allowMultiQueries = true và hoạt động tốt :)
Hazim

Cảm ơn bạn @RavinderReddy
Siva R

34

Bạn có thể sử dụng Cập nhật hàng loạt nhưng các truy vấn phải là hành động (nghĩa là chèn, cập nhật và xóa)

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
Bạn không thể sử dụng cách tiếp cận này cho các truy vấn "gọi tên mã ('abc', 984)"?
sebnukem 29/10/16

18

Gợi ý: Nếu bạn có nhiều thuộc tính kết nối thì hãy tách chúng bằng:

&

Để cung cấp cho bạn những thứ như:

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

Tôi hi vọng điêu nay se giup được ai đo.

Trân trọng,

Glyn


11

Dựa trên thử nghiệm của tôi, cờ đúng là "allowMultiQueries = true"


2

Tại sao bạn không thử và viết một Stored Procedurecho điều này?

Bạn có thể nhận Result Setra và trong cùng một cách Stored Procedurebạn có thể làm Insertnhững gì bạn muốn.

Điều duy nhất là bạn có thể không nhận được các hàng mới được chèn trong Result Setif you Insertafter the Select.


1
Không phải lúc nào bạn cũng có quyền viết Thủ tục được lưu trữ. Ví dụ: đó là cơ sở dữ liệu của khách hàng mà bạn chỉ được phép chọn từ đó.
pedram bashiri,

2

Tôi nghĩ đây là cách dễ nhất để lựa chọn / cập nhật / chèn / xóa khó khăn. Bạn có thể chạy bao nhiêu cập nhật / chèn / xóa tùy thích sau khi chọn (bạn phải chọn trước (giả nếu cần)) với executeUpdate (str) (chỉ cần sử dụng int mới (count1, count2, ...)) và nếu bạn cần một lựa chọn mới, hãy đóng 'câu lệnh' và 'kết nối' và tạo mới cho lựa chọn tiếp theo. Như ví dụ:

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

Tôi hy vọng nó sẽ giúp


1
Mở một kết nối DB là rất tốn kém. Không phải là một thực hành tốt để làm điều đó mọi lúc. Cái mà bạn đã đưa ra sẽ tạo ra n số DB lần truy cập cho n số truy vấn dẫn đến hiệu suất kém.
Arun Kumar Mudraboyina,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.