2009-06-08 9 views
6

Me gustaría utilizar declaraciones preparadas, para many reasons. Pero, me gustaría crear un método que tiene el siguiente aspecto:¿Por qué necesito una conexión para crear Declaracionesprecisas?

/* This opens a connection, executes the query, and closes the connection */ 
public static void executeNonQuery(String queryString); 

En otras palabras, quiero que mi lógica de la aplicación a sólo tienen que formular las consultas y se alimentan en los parámetros, pero no se ocupan de las conexiones & declaraciones . Sin embargo, las declaraciones preparadas se crean a partir de un objeto de conexión, por lo que actualmente me veo forzado a preparar la cadena de consulta utilizando String.format() - butt feo y peligroso.

¿Hay alguna manera de hacer lo que quiero sin utilizar String.format()?

+0

Su método executeNonQuery tiene un problema: obtener una conexión. Si crea uno cada vez que se ejecuta este método, tendrá problemas de ejecución una y otra vez (crear y cerrar conexiones es caro). Si esto está encapsulado en un objeto que crea una conexión solo en la primera llamada, tendrá un problema: ¿cuándo cerrarlo? Tal vez basado en el tiempo? Si usa campos estáticos para almacenar en caché, tenga cuidado de que esto no se recopile. Sin embargo, tenga cuidado con las llamadas concurrentes, al almacenar en caché una conexión: sin un mecanismo de bloqueo (como sincrónico), podría crear muchas conexiones. –

Respuesta

14

¿Por qué necesito una conexión para crear Declaracionesprecisas?

Porque las declaraciones se preparan por conexión en la mayoría de RDBMS.

Las declaraciones preparadas son, de hecho, planes de ejecución en caché que no tienen en cuenta los permisos, las codificaciones, la configuración de intercalación, etc.

Todo esto se hace durante el análisis de consultas.

¿Hay una manera de hacer lo que quiera sin necesidad de utilizar String.format()

No veo por qué necesita String.format() aquí.

Puede implementar su consulta como una clase, crear una conexión y preparar la consulta en el constructor de la clase y luego ejecutarla en un método.

Una consulta parametrizada típicamente se ve así:

SELECT * 
FROM table 
WHERE col1 = ? 
     AND col2 = ? 

, donde serán sustituidos los parámetros destino a ? 's durante la ejecución de la consulta.

Si desea un método static:

  • crear un identificador static conexión.
  • Cree una tabla hash static de consultas preparadas utilizando el texto de consulta parametrizado como key, y el identificador de la consulta preparada como value.
  • Cuando quiera ejecutar una consulta, encuentre su manejador (o créelo si no se encontró) y utilícelo para vincular los parámetros y ejecutar la consulta.
1

¿Por qué su lógica de "aplicación" no tiene una capa de datos creada que puede presentar ese tipo de método de interfaz?

Su capa de datos puede manejar la creación de conexiones, preparación de declaraciones, etc., todo dentro de ese método executeNonQuery.

Creo que si intenta fusionar los parámetros de su consulta/declaración usted mismo en un String, entonces se está disparando en el pie y en realidad no usa la funcionalidad de los parámetros de PreparedStatements. No estoy seguro de por qué querrías hacer esto.

También puede considerar el uso de una API como Spring, que tiene una serie de clases JdbcTemplate que pueden abstraer todo el manejo de la conexión lejos de usted, pero aún le permiten trabajar con parámetros en Map.

0

Extracto de todas las cosas JDBC al tener una clase que llamo QueryRunner que tiene un método de ejecución que toma el sql, una lista de objetos que representan los parámetros y un objeto que procesará el ResultSet. Si usa el método setObject de JDBC para establecer sus parámetros, descubrirá los tipos de DB apropiados para usar en base al objeto subyacente. Aquí hay una parte de mi código. Tengo otro método que envuelve este y obtiene la conexión.

public void executeNoCommit(Connection conn, 
          String sql, 
          List params, 
          ResultSetProcessor processor) throws SQLException { 
    PreparedStatement stmt = null; 
    ResultSet rs = null; 
    int updateCount = 0; 
    Iterator it; 
    int paramIndex = 1; 
    boolean query; 

    try { 
     stmt = conn.prepareStatement(sql); 

     if (params != null) { 
      it = params.iterator(); 
      while (it.hasNext()) { 
       stmt.setObject(paramIndex, it.next()); 
       paramIndex++; 
      } 
     } 

     query = stmt.execute(); 
     if (query) { 
      rs = stmt.getResultSet(); 
     } 
     else { 
      updateCount = stmt.getUpdateCount(); 
     } 

     processor.process(rs, updateCount); 
    } 
    finally { 
     if (rs != null) { 
      try { 
       rs.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 

     if (stmt != null) { 
      try { 
       stmt.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 
    } 
} 
+0

¿Se puede publicar el código? – ripper234

0

Es posible que desee algo así como el paquete dbUtils en las bibliotecas Apache Commons: [http://commons.apache.org/dbutils/index.html][1]

La clase QueryRunner le permite ejecutar sentencias SQL sin tener que crear manualmente PreparedStatements, o incluso tener una conexión abierta para ese importar. Desde la página de ejemplos:

QueryRunner run = new QueryRunner(dataSource); 
try 
{ 
    // Create an object array to hold the values to insert 
    Object[] insertParams = {"John Doe", new Double(1.82)}; 
    // Execute the SQL update statement and return the number of 
    // inserts that were made 
    int inserts = run.update("INSERT INTO Person (name,height) VALUES (?,?)", 
           insertParams); 

    // Now it's time to rise to the occation... 
    Object[] updateParams = {new Double(2.05), "John Doe"}; 
    int updates = run.update("UPDATE Person SET height=? WHERE name=?", 
           updateParams); 
} 
catch(SQLException sqle) { 
    // Handle it 
} 

Así que básicamente se encarga de la creación de declaraciones preparadas de forma transparente, y la única cosa que realmente necesita saber es una fuente de datos. Esto también funciona igual para las instrucciones que no son de actualización/inserción, es decir, las consultas de selección simples, y la capacidad de crear ResultSetHandlers le da la capacidad de convertir un ResultSet en algo así como un bean completamente preparado o un Map con las claves siendo los nombres de columna, y los valores siendo los valores de fila reales. Muy útil para cuando no puede implementar una solución ORM completa.

Cuestiones relacionadas