Múltiplas consultas executadas em java em uma única instrução


100

Oi, eu queria saber se é possível executar algo assim usando JDBC, pois atualmente fornece uma exceção, embora seja possível no navegador de consulta MySQL.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Embora eu saiba que é possível ter a string de consulta SQL sendo dividida e a instrução executada duas vezes, mas eu queria saber se existe uma abordagem única para isso.

    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
colocado em um procedimento armazenado, chame o procedimento armazenado. significa que você também não precisa reimplantar seu código quando quiser fazer uma alteração.
Chris

4
Há uma propriedade que você deve definir na string de conexão allowMultiQueries=true.
Rahul

provável duplicata: Como executar consultas sql compostas em java? [1] [1]: stackoverflow.com/questions/6773393/…
prayagupd

1
Oi Rahul, para este projeto estou usando um objeto de conexão simples e antigo e você sabe onde devo definir "allowMultiQueries = true".
Adicionei

Respostas:


140

Eu queria saber se é possível executar algo assim usando JDBC.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Sim, é possível. Existem duas maneiras, pelo que eu sei. Eles são

  1. Definindo a propriedade de conexão do banco de dados para permitir várias consultas, separadas por um ponto e vírgula por padrão.
  2. Chamando um procedimento armazenado que retorna cursores implícitos.

Os exemplos a seguir demonstram as duas possibilidades acima.

Exemplo 1 : (para permitir consultas múltiplas):

Ao enviar uma solicitação de conexão, você precisa anexar uma propriedade de conexão allowMultiQueries=trueao url do banco de dados. Este é propriedade de conexão adicional para aqueles que já existe alguns, como autoReConnect=true, etc .. Os valores aceitáveis para allowMultiQueriespropriedade são true, false, yes, e no. Qualquer outro valor é rejeitado em tempo de execução com um SQLException.

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

A menos que tal instrução seja passada, um SQLExceptioné lançado.

Você tem que usar execute( String sql )ou suas outras variantes para buscar os resultados da execução da consulta.

boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );

Para iterar e processar os resultados, você precisa das seguintes etapas:

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

Exemplo 2 : etapas a seguir:

  1. Crie um procedimento com um ou mais select, e DMLconsultas.
  2. Chame de java usando CallableStatement.
  3. Você pode capturar vários ResultSets executados no procedimento.
    Os resultados de DML não podem ser capturados, mas podem emitir outro select
    para descobrir como as linhas são afetadas na tabela.

Tabela de amostra e procedimento :

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)

Procedimento de chamada 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

Infelizmente, isso não funciona com a versão incorporada do Derby.
user2428118

@ user2428118: Motivo? Algum erro observado? Você verificou se o driver é compatível com este recurso?
Ravinder Reddy

adicionei allowMultiQueries = true e funciona bem :)
Hazim

Obrigado @RavinderReddy
Siva R

34

Você pode usar a atualização em lote, mas as consultas devem ser de ação (ou seja, inserir, atualizar e excluir) consultas

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
Você não pode usar essa abordagem para consultas "call sprocname ('abc', 984)"?
sebnukem

18

Dica: se você tiver mais de uma propriedade de conexão, separe-as com:

&

Para lhe dar algo como:

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

Espero que isso ajude alguém.

Saudações,

Glyn


11

Com base em meus testes, o sinalizador correto é "allowMultiQueries = true"


2

Por que você não tenta escrever um Stored Procedurepara isso?

Você pode obter o Result Setpara fora e no mesmo Stored Procedurevocê pode Inserto que quiser.

A única coisa é que você pode não obter as linhas recém-inseridas no Result Setse Insertdepois de Select.


1
Você nem sempre tem permissão para escrever um procedimento armazenado. Por exemplo, é um banco de dados de cliente que você só tem permissão para selecionar.
pedram bashiri

2

Eu acho que esta é a maneira mais fácil de selecionar / atualizar / inserir / excluir multy. Você pode executar quantas atualizações / inserções / exclusões desejar após a seleção (você deve fazer uma seleção primeiro (um fictício se necessário)) com executeUpdate (str) (apenas use new int (contagem1, contagem2, ...)) e se vc precisar de uma nova seleção feche 'instrução' e 'conexão' e faça uma nova para a próxima seleção. Por exemplo:

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

Espero que ajude


1
Abrir uma conexão de banco de dados é muito mais caro. Não é uma boa prática fazer isso sempre. O que você forneceu deve gerar n número de ocorrências do banco de dados para n número de consultas, o que leva a um desempenho ruim.
Arun Kumar Mudraboyina
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.