2009-06-08 12 views
6

Vorrei utilizzare istruzioni preparate, per many reasons. Ma, vorrei creare un metodo che assomiglia a questo:Perché ho bisogno di una connessione per creare PreparedStatements?

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

In altre parole, voglio la mia logica dell'applicazione di avere solo per formulare le domande e nutrire nei parametri, ma non trattare con le connessioni & dichiarazioni . Tuttavia, PreparedStatements viene creato da un oggetto di connessione, quindi sono attualmente costretto a preparare la stringa di query usando String.format() - brutto e pericoloso.

C'è un modo per fare ciò che voglio senza utilizzare String.format()?

+0

Il metodo executeNonQuery ha un problema: ottenere una connessione. Se ne crei uno ogni volta che viene eseguito questo metodo, i problemi di prestazioni si ripetono continuamente (la creazione e la chiusura delle connessioni sono costose). Se questo è incapsulato su un oggetto che crea una connessione solo alla prima chiamata, si avrà un problema: quando chiuderlo? Forse in base al tempo? Se si utilizzano i campi statici nella cache, fare attenzione che questo non venga raccolto. Attenzione alle chiamate simultanee, quando si effettua il caching di una connessione, tuttavia: senza un meccanismo di blocco (come syncrhonized), è possibile creare molte connessioni. –

risposta

14

Perché è necessaria una connessione per creare PreparedStatements?

Poiché le istruzioni vengono preparate in base alla connessione nella maggior parte degli RDBMS.

Le istruzioni preparate sono in effetti piani di esecuzione memorizzati nella cache che non consentono di tenere conto di autorizzazioni, codifiche, impostazioni di fascicolazione ecc.

Tutto ciò viene eseguito durante l'analisi della query.

C'è un modo per fare quello che voglio senza utilizzare String.format()

Non vedo perché è necessario String.format() qui.

È possibile implementare la query come classe, creare una connessione e preparare la query nel costruttore della classe e quindi eseguirla in un metodo.

Una query parametrizzata appare tipicamente simili:

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

, dove verranno sostituiti i parametri legati per ? 's durante l'esecuzione di query.

Se si desidera un metodo static:

  • Creare una maniglia static connessione.
  • Creare una tabella hash static di query preparate utilizzando il testo della query parametrizzata come key e l'handle per la query preparata come value.
  • Ogni volta che si desidera eseguire una query, individuarne l'handle (o crearlo se non è stato trovato) e utilizzare per associare i parametri ed eseguire la query.
1

Perché la logica di "applicazione" non utilizza un livello dati creato che può presentare quel tipo di metodo di interfaccia?

Il livello dati può quindi gestire la creazione di connessioni, preparare istruzioni ecc., Tutto all'interno del metodo executeNonQuery.

Penso che se si sta tentando di unire i parametri nella query/istruzione in una stringa, quindi si sta sparando in piedi e in realtà non utilizzando la funzionalità dei parametri di PreparedStatements. Non sono sicuro del perché vorresti farlo.

Si potrebbe anche voler utilizzare un'API come Spring, che ha una serie di classi JdbcTemplate che possono astrarre tutta la gestione della connessione, ma consentono comunque di lavorare con i parametri in un Map.

0

Estraggo tutto il materiale JDBC avendo una classe che richiamo QueryRunner che ha un metodo execute che accetta lo sql, un elenco di oggetti che rappresentano i parametri e un oggetto che elaborerà il ResultSet. Se si utilizza il metodo setObject di JDBC per impostare i parametri, verranno determinati i tipi di DB appropriati da utilizzare in base all'oggetto sottostante. Ecco una parte del mio codice. Ho un altro metodo che avvolge questo e ottiene la connessione.

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

Puoi pubblicare il codice? – ripper234

0

Probabilmente si desidera qualcosa di simile al pacchetto di DbUtils nelle librerie di Apache Commons: [http://commons.apache.org/dbutils/index.html][1]

La classe QueryRunner consente di eseguire istruzioni SQL, senza dover creare manualmente PreparedStatements, o addirittura avere una connessione aperta per quella importa. Dalla pagina esempi:

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 
} 

Così gestisce fondamentalmente la creazione di istruzioni preparate in modo trasparente, e l'unica cosa che si ha realmente bisogno di sapere è un DataSource. Questo funziona anche per le istruzioni non-update/insert, ovvero per le query select plain-vanilla, e la possibilità di creare ResultSetHandlers ti dà la possibilità di convertire un ResultSet in qualcosa come un bean completamente preparato o una Map con le chiavi essendo i nomi delle colonne e i valori come valori effettivi delle righe. Molto utile per quando non è possibile implementare un'intera soluzione ORM.

Problemi correlati