2012-05-29 15 views
70

Hola, me preguntaba si es posible ejecutar algo como esto usando JDBC, ya que actualmente ofrece una excepción aunque sea posible en el navegador de consultas MySQL.Múltiples consultas ejecutadas en java en una sola declaración

"SELECT FROM * TABLE;INSERT INTO TABLE;" 

Aunque soy consciente de que es posible tener con la cadena de consulta SQL que es partida y la sentencia ejecutada dos veces, pero me preguntaba si hay un enfoque de un solo tiempo 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

+3

Hay una propiedad que debe establecerse en la cadena de conexión 'allowMultiQueries = true'. – Rahul

+0

duplicado probable: ¿cómo ejecutar consultas SQL compuestas en java? [1] [1]: http://stackoverflow.com/questions/6773393/how-to-execute-composite-sql-queries-in-java – prayagupd

Respuesta

100

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. Al establecer propiedad de conexión de base de datos para permitir que varias consultas, separados por un punto y coma de manera predeterminada.
  2. Llamando a un procedimiento almacenado que devuelve los cursores implícitos.

Los siguientes ejemplos demuestran las dos posibilidades anteriores.

Ejemplo 1: (Para permitir que varias consultas):

Mientras que el envío de una solicitud de conexión, es necesario añadir una propiedad de conexión allowMultiQueries=true a la URL base de datos. Esta es una propiedad de conexión adicional a aquellos si ya existe algunos, como autoReConnect=true, etc. Los valores aceptables para allowMultiQueries son true, false, yes y no. Cualquier otro valor se rechaza en el tiempo de ejecución con un SQLException.

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

menos que se apruebe dicha instrucción, un SQLException se lanza.

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 a través de y el proceso de resultados que usted requiere pasos siguientes:

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. crear un procedimiento con uno o más select, y DML consultas.
  2. Llámalo desde java usando CallableStatement.
  3. Puede capturar múltiples ResultSet s ejecutados en el procedimiento.
    Los resultados DML no se pueden capturar pero pueden emitir otro select
    para encontrar cómo las filas se ven afectadas en la tabla.

Tabla de muestras y el 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) 

llamada a procedimiento 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 
+0

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

+0

@ user2428118: ¿Motivo? Cualquier error observado? ¿Revisó si el controlador admite esta característica? –

+0

he agregado allowMultiQueries = verdadero y funciona bien :) – Hazim

0

¿Por qué no intentas escribir un Stored Procedure para esto?

Puede obtener el Result Set y en el mismo Stored Procedure puede Insert lo que quiere.

Lo único es que es posible que no obtenga las filas recién insertadas en el Result Set si Insert después del Select.

21

Usted puede usar la actualización por lotes pero las consultas deben ser de acción (es decir. Insertar, actualizar y eliminar) 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(); 
+0

. No se puede usar este enfoque para las consultas de "call sprocname ('abc', 984)"? – sebnukem

7

Basado en mis pruebas, la bandera correcta es "allowMultiQueries = true"

12

Sugerencia: si tiene más de una conexión propiedad cción luego separarlos con:

& 

Para darle algo como:

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

espero que esto ayude a alguien.

Saludos,

Glyn

0

creo que esta es la manera más fácil para la selección multy/actualizar/insertar/borrar. Puede ejecutar tantas actualizaciones/insertar/eliminar como desee después de seleccionar (tiene que hacer una selección primero (una variable ficticia si es necesario)) con executeUpdate (str) (simplemente use new int (count1, count2, ...)) y si necesita una nueva selección, cierre 'declaración' y 'conexión' y haga nueva 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 hacer eso cada vez. Lo que ha dado debe hacer n hits de DB para n cantidad de consultas que conducen a un bajo rendimiento. –

Cuestiones relacionadas