Varias consultas ejecutadas en java en una sola declaración


100

Hola, me preguntaba si es posible ejecutar algo como esto usando JDBC, ya que actualmente proporciona una excepción a pesar de que es posible en el navegador de consultas MySQL.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Si bien me doy cuenta de que es posible dividir la cadena de consulta SQL y ejecutar la declaración dos veces, me preguntaba si hay un enfoque único para esto.

    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
poner en un procedimiento almacenado, llamar al procedimiento almacenado. significa que tampoco tiene que volver a implementar su código cuando desee realizar un cambio.
Chris

4
Hay una propiedad que debe establecer en la cadena de conexión allowMultiQueries=true.
Rahul

probable duplicado: ¿Cómo ejecutar consultas SQL compuestas en Java? [1] [1]: stackoverflow.com/questions/6773393/…
prayagupd

1
Hola Rahul, para este proyecto estoy usando un objeto de conexión antiguo simple y ¿sabes dónde debo establecer "allowMultiQueries = true"? Se agregó el código de objeto de conexión en la pregunta
MilindaD

Respuestas:


140

Me preguntaba si es posible ejecutar algo como esto usando JDBC.

"SELECT FROM * TABLE;INSERT INTO TABLE;"

Sí, es posible. Hay dos formas, hasta donde yo sé. Son

  1. Estableciendo la propiedad de conexión de la base de datos para permitir múltiples consultas, separadas por un punto y coma por defecto.
  2. Llamando a un procedimiento almacenado que devuelve cursores implícitos.

Los siguientes ejemplos demuestran las dos posibilidades anteriores.

Ejemplo 1 : (para permitir múltiples consultas):

Al enviar una solicitud de conexión, debe agregar una propiedad de conexión allowMultiQueries=truea la URL de la base de datos. Esto es propiedad de conexión adicionales a los que ya existe, si algunos, como autoReConnect=true, etc .. Los valores aceptables para allowMultiQueriesla propiedad son true, false, yes, y no. Cualquier otro valor se rechaza en tiempo de ejecución con un SQLException.

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

A menos que se apruebe tal instrucción, SQLExceptionse lanza un.

Debe usar execute( String sql )o sus otras variantes para obtener resultados de la ejecución de la consulta.

boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );

Para iterar y procesar los resultados, necesita los siguientes pasos:

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

Ejemplo 2 : Pasos a seguir:

  1. Cree un procedimiento con una o más consultas selecty DML.
  2. Llámelo desde java usando CallableStatement.
  3. Puede capturar varios mensajes de correo ResultSetelectrónico ejecutados en el procedimiento.
    Los resultados de DML no se pueden capturar, pero pueden emitir otro select
    para averiguar cómo se ven afectadas las filas en la tabla.

Tabla de muestra y procedimiento :

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)

Procedimiento de llamada desde 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

Desafortunadamente, esto no funciona con la versión integrada de Derby.
user2428118

@ user2428118: ¿Razón? ¿Algún error observado? ¿Comprobó si Driver admite esta función?
Ravinder Reddy

He agregado allowMultiQueries = true y funciona bien :)
Hazim

Gracias @RavinderReddy
Siva R

34

Puede utilizar la actualización por lotes, pero las consultas deben ser consultas de acción (es decir, insertar, actualizar y eliminar)

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
¿No puede utilizar este enfoque para las consultas "call sprocname ('abc', 984)"?
sebnukem

18

Sugerencia: si tiene más de una propiedad de conexión, sepárelas con:

&

Para darte algo como:

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

Espero que esto ayude a alguien.

Saludos,

Glyn


11

Según mis pruebas, la marca correcta es "allowMultiQueries = true"


2

¿Por qué no intentas escribir una Stored Procedurepara esto?

Puedes sacar la Result Setsalida y en la misma Stored Procedurepuedes hacer Insertlo que quieras.

Lo único es que es posible que no obtenga las filas recién insertadas en el Result Setsi Insertdespués del Select.


1
No siempre tiene permiso para escribir un procedimiento almacenado. Por ejemplo, es la base de datos de un cliente de la que solo puede seleccionar.
pedram bashiri

2

Creo que esta es la forma más fácil de realizar múltiples selecciones / actualizar / insertar / eliminar. Puede ejecutar tantas actualizaciones / insertar / eliminar como desee después de la selección (primero debe hacer una selección (una ficticia si es necesario)) con executeUpdate (str) (solo use new int (count1, count2, ...)) y si necesita una nueva selección, cierre 'declaración' y 'conexión' y haga nuevas para la próxima selección. Como ejemplo:

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 ayude


1
Abrir una conexión de base de datos es muy costoso. No es una buena práctica hacerlo todo el tiempo. El que ha proporcionado debe hacer n números DB hits para n número de consultas, lo que conduce a un rendimiento deficiente.
Arun Kumar Mudraboyina
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.