2012-10-18 17 views
12

Quando si utilizza JDBC in Java, il metodo generalmente accettato di interrogare un database è acquisire una connessione, creare un'istruzione da quella connessione e quindi eseguire una query da tale istruzione.Modo preferito per interrogare un database più volte?

// load driver 
Connection con = DriverManager.getConnection(..); 
Statement stmt = con.createStatement(); 
ResultSet result = stmt.executeQuery("SELECT.."); 
// ... 

Tuttavia, non sono sicuro di come trattare una seconda query per lo stesso database.

  1. Può un'altra query essere eseguito in modo sicuro sullo stesso Statement oggetto, o devono un'altra dichiarazione essere creati dall'oggetto Connection al fine di eseguire un'altra query?

  2. Se lo stesso Statement oggetto può essere utilizzato per più query, qual è lo scopo della classe Statement (in quanto sarebbe allora più sensato per un metodo Connection.executeQuery() di esistere)?

+4

Per la prima parte, hai provato a farlo da solo? Hai avuto eccezioni o output indesiderati? –

+1

Ci sono un sacco di esempi nel web. Potresti guardarli laggiù, provare te stesso e se ottieni un'eccezione o problemi migliorare la tua domanda, in modo che possiamo aiutarti a essere più precisi. – user

+0

@RohitJain Non ce l'ho, ma sono quasi sicuro che diverse query possano essere eseguite dalla stessa opzione Statement, il che mi porta a chiedermi se ci sono degli svantaggi o dei problemi di sicurezza nel fare ciò (domanda 1), e come risultato , qual è il punto della classe Statement (domanda 2). – Vulcan

risposta

7

Sì, è possibile riutilizzare l'oggetto Statement, ma i ResultSet oggetti restituiti dalla executeQuery chiude già aperto di risultati.

Vedere la javadoc per la spiegazione

Per default, solo un oggetto ResultSet per oggetto Statement può essere aperto allo stesso tempo. Pertanto, se la lettura di un oggetto ResultSet è interlacciata con la lettura di un altro, ognuno deve essere stato generato da diversi oggetti Statement. Tutti i metodi di esecuzione nell'interfaccia Statement chiudono implicitamente l'oggetto ResultSet corrente di una statistica se esiste uno aperto.

Quindi la seguenti situazioni:

// load driver 
Connection con = DriverManager.getConnection(..); 
Statement stmt = con.createStatement(); 
ResultSet result = stmt.executeQuery("select .."); 
// do something with result ... or not 
ResultSet result2 = stmt.executeQuery("select ..."); 
// result is now closed, you cannot read from it anymore 
// do something with result2 
stmt.close(); // will close the resultset bound to it 

Ad esempio è possibile trovare un'implementazione open source della dichiarazione nel progetto jTDS. Nella Statement.executeQuery() method è possibile vedere una chiamata a initialize() che closes all the resultsets già aperto

protected void initialize() throws SQLException { 
    updateCount = -1; 
    resultQueue.clear(); 
    genKeyResultSet = null; 
    tds.clearResponseQueue(); 
    // FIXME Should old exceptions found now be thrown instead of lost? 
    messages.exceptions = null; 
    messages.clearWarnings(); 
    closeAllResultSets(); 
} 
+0

Se tutti i metodi di esecuzione chiudono implicitamente il ResultSet corrente di un'istruzione (se aperto), è necessario chiudere esplicitamente un ResultSet prima di eseguire un'altra query? – Vulcan

+0

@Vulcan hai ragione, come hai notato e come si dice in javadoc, i metodi 'execute *()' su un 'Statement' sembra chiudere qualsiasi' ResultSet' aperto che ne deriva, quindi in pratica è non è obbligatorio chiamare 'close()' su di esso prima di eseguire un nuovo execute, ma è buona pratica chiudere le risorse che hai aperto. – Alex

+0

Vedere la mia modifica per l'implementazione open source jTDS come esempio. – Alex

1

bene, questo è il motivo per cui abbiamo il concetto di classi in programmazione orientata agli oggetti. Una classe definisce i membri costitutivi che abilitano le sue istanze allo stato e al comportamento. Qui la dichiarazione si occupa di tutto ciò che riguarda una dichiarazione SQL. Esistono così tante altre funzioni che potrebbero essere eseguite come query batch ecc.

3

A livello di codice, è possibile riutilizzare la stessa connessione e la stessa istruzione per più di una query e chiudere la dichiarazione e la connessione alla fine.

Tuttavia, questa non è una buona pratica. Le prestazioni dell'applicazione sono molto sensibili al modo in cui si accede al database. Idealmente, ogni connessione dovrebbe essere aperta per il minor tempo possibile. Quindi, le connessioni devono essere raggruppate. Passando da quello, si racchiudere ogni query in un blocco di {open connection, create a prepared statement, run query, close statement, close connection}. Questo è anche il modo in cui vengono implementati la maggior parte dei modelli SQL. Se la concorrenza lo consente, è possibile attivare più query allo stesso tempo utilizzando un pool di thread.

+0

Sembra ragionevole, ma qual è il ragionamento alla base della connessione aperta per il minor tempo possibile? È meglio tenere aperta una connessione per gestire 10 query al minuto o aprire una nuova connessione una media di una volta ogni 6 secondi? – Vulcan

+0

@Vulcan Non è la stessa cosa. Hai la connessione aperta il minor tempo e poi si torna alla piscina. La piscina manterrà la connessione aperta per te. Perché "chiudi" la connessione ogni volta che sei sicuro che sia sempre tornato al pool. Se lo gestisci da solo, i rischi aumentano man mano che ti perdi la chiusura e corri in sessioni di database o problemi di porri di memoria. –

1

Di solito, è una dichiarazione per una query.Potrebbe non essere necessario farlo ma quando si scrive un'applicazione reale, non si desidera ripetere più volte gli stessi passaggi. Questo è contro il principale di DRY, in più sarà anche più complicato man mano che l'applicazione cresce.

È utile scrivere oggetti che gestiranno questo tipo di materiale di basso livello (ripetitivo) e fornire diversi metodi per accedere a db fornendo le query.

1

Non mi preoccuperei di creare nuove istruzioni. Tuttavia, l'apertura di una connessione al database può richiedere un uso intensivo delle risorse e l'apertura e la chiusura delle connessioni influiscono sulle prestazioni.

Lasciando le connessioni in qualche modo di autogestione di solito è piuttosto male.

Si consiglia di utilizzare connection pooling. Di solito ti lanci un commando vicino, ma stai solo restituendo quella connessione alla piscina. Quando richiedi una nuova connessione, riutilizzerà la connessione restituita in precedenza.

Si consiglia di avere istruzioni diverse per una connessione. La dichiarazione è un'implementazione e un'interfaccia. A seconda di ciò che ti serve, a volte desideri utilizzare lo CallableStatment. Alcune logiche possono essere riutilizzate quando richiesto.

+0

Grazie, non ho mai incontrato il pool di connessioni prima e sembra un concetto estremamente utile che userò nella mia applicazione server. – Vulcan

+0

@Vulcan Se l'applicazione server è un'applicazione Web, il server delle applicazioni può eseguire il pool di connessioni. La configurazione deve essere descritta nel server delle applicazioni. Altrimenti potresti usare http://commons.apache.org/dbcp/ o qualche altro set di strumenti a tua scelta. –

+0

Le mie scuse, non credo di essere stato chiaro con questa affermazione; è semplicemente un'applicazione Java che ospita un socket server per i socket client a cui connettersi. – Vulcan

2

Ho una cosa da aggiungere se si utilizza Connection e Statement in un ambiente con thread. La mia esperienza mostra che stmt.executeQuery (..) è stato salvato per l'uso in un ambiente parallelo ma con la conseguenza che ogni query viene serializzata e quindi elaborata in sequenza, senza produrre alcuna accelerazione. Quindi è meglio usare una nuova connessione (non una dichiarazione) per ogni thread.

Per un ambiente sequenziale standard, la mia esperienza ha dimostrato che il riutilizzo di istruzioni non è affatto un problema e che i ResultSet non devono necessariamente essere chiusi manualmente.

+0

L'ho trovato estremamente utile, poiché * sto * usando Connection e Statement in un ambiente con thread. In combinazione con la risposta di * Udo Held *, mi sento come se avessi imparato di cosa ho bisogno per le connessioni di database multi-threaded. – Vulcan

Problemi correlati