update statement preparedstatement prepared parametros los funcionamiento example consultas con java sql jdbc prepared-statement

parametros - preparedstatement java update



¿Cómo puedo obtener el SQL de un estado preparado? (11)

Tengo un método general de Java con la siguiente firma de método:

private static ResultSet runSQLResultSet(String sql, Object... queryParams)

Abre una conexión, crea un PreparedStatement utilizando la sentencia sql y los parámetros en la matriz de longitud variable queryParams , la ejecuta, almacena en caché el ResultSet (en CachedRowSetImpl ), cierra la conexión y devuelve el conjunto de resultados en caché.

Tengo manejo de excepciones en el método que registra errores. Registro la instrucción SQL como parte del registro, ya que es muy útil para la depuración. Mi problema es que el registro de la variable String sql registra la declaración de la plantilla con? S en lugar de los valores reales. Quiero registrar la declaración real que se ejecutó (o intenté ejecutar).

Entonces ... ¿Hay alguna forma de obtener la declaración SQL real que ejecutará un PreparedStatement ? ( Sin construirlo yo mismo. Si no puedo encontrar una manera de acceder al SQL PreparedStatement''s , probablemente termine compilándolo yo mismo en mi catch ).


Code Snippet para convertir SQL PreparedStaments con la lista de argumentos. Esto funciona para mi

/** * * formatQuery Utility function which will convert SQL * * @param sql * @param arguments * @return */ public static String formatQuery(final String sql, Object... arguments) { if (arguments != null && arguments.length <= 0) { return sql; } String query = sql; int count = 0; while (query.matches("(.*)//?(.*)")) { query = query.replaceFirst("//?", "{" + count + "}"); count++; } String formatedString = java.text.MessageFormat.format(query, arguments); return formatedString; }


Estoy usando Java 8, controlador JDBC con conector MySQL v. 5.1.31.

Puedo obtener una cadena SQL real usando este método:

// 1. make connection somehow, it''s conn variable // 2. make prepered statement template PreparedStatement stmt = conn.prepareStatement( "INSERT INTO oc_manufacturer" + " SET" + " manufacturer_id = ?," + " name = ?," + " sort_order=0;" ); // 3. fill template stmt.setInt(1, 23); stmt.setString(2, ''Google''); // 4. print sql string System.out.println(((JDBC4PreparedStatement)stmt).asSql());

Así que vuelve algo así:

INSERT INTO oc_manufacturer SET manufacturer_id = 23, name = ''Google'', sort_order=0;


Estoy usando Oralce 11g y no pude obtener el SQL final de PreparedStatement. Después de leer la respuesta de @Pascal MARTIN, entiendo por qué.

Acabo de abandonar la idea de usar PreparedStatement y utilicé un formateador de texto simple que se ajustaba a mis necesidades. Aquí está mi ejemplo:

//I jump to the point after connexion has been made ... java.sql.Statement stmt = cnx.createStatement(); String sqlTemplate = "SELECT * FROM Users WHERE Id IN ({0})"; String sqlInParam = "21,34,3434,32"; //some random ids String sqlFinalSql = java.text.MesssageFormat(sqlTemplate,sqlInParam); System.out.println("SQL : " + sqlFinalSql); rsRes = stmt.executeQuery(sqlFinalSql);

Se da cuenta de que sqlInParam se puede construir dinámicamente en un ciclo (for, while). Simplemente hice simple llegar al punto de utilizar la clase MessageFormat para servir como un formateador de plantilla de cadena para la consulta SQL.


Extraje mi sql de PreparedStatement usando preparedStatement.toString () En mi caso, toString () devuelve String así:

org.hsqldb.jdbc.JDBCPreparedStatement@7098b907[sql=[INSERT INTO TABLE_NAME(COLUMN_NAME, COLUMN_NAME, COLUMN_NAME) VALUES(?, ?, ?)], parameters=[[value], [value], [value]]]

Ahora he creado un método (Java 8), que está usando regex para extraer tanto la consulta como los valores y ponerlos en el mapa:

private Map<String, String> extractSql(PreparedStatement preparedStatement) { Map<String, String> extractedParameters = new HashMap<>(); Pattern pattern = Pattern.compile(".*//[sql=//[(.*)],//sparameters=//[(.*)]].*"); Matcher matcher = pattern.matcher(preparedStatement.toString()); while (matcher.find()) { extractedParameters.put("query", matcher.group(1)); extractedParameters.put("values", Stream.of(matcher.group(2).split(",")) .map(line -> line.replaceAll("(//[|])", "")) .collect(Collectors.joining(", "))); } return extractedParameters; }

Este método devuelve el mapa donde tenemos pares clave-valor:

"query" -> "INSERT INTO TABLE_NAME(COLUMN_NAME, COLUMN_NAME, COLUMN_NAME) VALUES(?, ?, ?)" "values" -> "value, value, value"

Ahora - si quiere valores como lista, simplemente puede usar:

List<String> values = Stream.of(yourExtractedParametersMap.get("values").split(",")) .collect(Collectors.toList());

Si su preparedStatement.toString () es diferente que en mi caso, solo es cuestión de "ajustar" la expresión regular.


Implementé el siguiente código para imprimir SQL desde PrepareStatement

public void printSqlStatement(PreparedStatement preparedStatement, String sql) throws SQLException{ String[] sqlArrya= new String[preparedStatement.getParameterMetaData().getParameterCount()]; try { Pattern pattern = Pattern.compile("//?"); Matcher matcher = pattern.matcher(sql); StringBuffer sb = new StringBuffer(); int indx = 1; // Parameter begin with index 1 while (matcher.find()) { matcher.appendReplacement(sb,String.valueOf(sqlArrya[indx])); } matcher.appendTail(sb); System.out.println("Executing Query [" + sb.toString() + "] with Database[" + "] ..."); } catch (Exception ex) { System.out.println("Executing Query [" + sql + "] with Database[" + "] ..."); } }


No está definido en ningún lugar en el contrato API de JDBC, pero si tiene suerte, el controlador JDBC en cuestión puede devolver el SQL completo al llamar a PreparedStatement#toString() . Es decir

System.out.println(preparedStatement);

Al menos, los controladores JDBC de MySQL 5.x y PostgreSQL 8.x lo admiten. Sin embargo, la mayoría de los demás controladores JDBC no lo admiten. Si tiene uno, su mejor Log4jdbc es usar Log4jdbc o P6Spy .

Alternativamente, también puede escribir una función genérica que toma una Connection , una cadena SQL y los valores de la declaración y devuelve un estado PreparedStatement después de registrar la cadena SQL y los valores. Ejemplo de lanzamiento:

public static PreparedStatement prepareStatement(Connection connection, String sql, Object... values) throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < values.length; i++) { preparedStatement.setObject(i + 1, values[i]); } logger.debug(sql + " " + Arrays.asList(values)); return preparedStatement; }

y usarlo como

try { connection = database.getConnection(); preparedStatement = prepareStatement(connection, SQL, values); resultSet = preparedStatement.executeQuery(); // ...

Otra alternativa es implementar un PreparedStatement personalizado que envuelve (decora) el estado real de PreparedStatement en la construcción y reemplaza todos los métodos para que llame a los métodos del real PreparedStatement y recolecte los valores en todos los métodos setXXX() y construya perezosamente el "real" "Cadena SQL cuando se executeXXX() uno de los métodos executeXXX() (todo un trabajo, pero la mayoría de los IDE proporcionan autogeneradores para los métodos de decorador, Eclipse lo hace). Finalmente solo utilízalo en su lugar. Eso también es básicamente lo que P6Spy y consortes ya hacen bajo los capós.


Para hacer esto, necesita una conexión JDBC y / o un controlador que admita el registro de sql en un nivel bajo.

Eche un vistazo a log4jdbc


Si está ejecutando la consulta y esperando un ResultSet (se encuentra en este escenario, al menos), entonces simplemente puede llamar a getStatement() ResultSet de la getStatement() manera:

ResultSet rs = pstmt.executeQuery(); String executedQuery = rs.getStatement().toString();

La variable executedQuery contendrá la declaración que se usó para crear el ResultSet .

Ahora, me doy cuenta de que esta pregunta es bastante antigua, pero espero que esto ayude a alguien ...


Si está utilizando MySQL, puede registrar las consultas utilizando el registro de consultas de MySQL . No sé si otros proveedores ofrecen esta característica, pero es probable que sí lo hagan.


Simplemente funciona:

public static String getSQL (Statement stmt){ String tempSQL = stmt.toString(); //please cut everything before sql from statement //javadb...: int i1 = tempSQL.indexOf(":")+2; tempSQL = tempSQL.substring(i1); return tempSQL; }

Está bien también para el Estado preparado.


Usando declaraciones preparadas, no hay "consulta SQL":

  • Usted tiene una declaración, que contiene marcadores de posición
    • se envía al servidor de base de datos
    • y preparado allí
    • lo que significa que la declaración SQL es "analizada", analizada, alguna estructura de datos que la representa está preparada en memoria
  • Y, entonces, tienes variables vinculadas
    • que se envían al servidor
    • y la declaración preparada se ejecuta - trabajando en esos datos

Pero no hay una reconstrucción de una consulta SQL real real, ni en Java ni en la base de datos.

Por lo tanto, no hay forma de obtener el SQL de la sentencia preparada, ya que no existe tal SQL.


Para fines de depuración, las soluciones son:

  • Ouput el código de la declaración, con los marcadores de posición y la lista de datos
  • O para "generar" alguna consulta SQL "a mano".