2010-04-26 8 views
7

Sono ancora uno studente che lavora a tempo parziale e quindi cerco sempre di essere consapevole dei modi migliori per fare le cose. Recentemente ho dovuto scrivere un programma per il lavoro in cui il thread principale del programma generava i thread "task" (per ogni record "task" db) che eseguiva alcune operazioni e quindi aggiornava il record per dire che è terminato. Quindi avevo bisogno di un oggetto di connessione al database e degli oggetti PreparedStatement in o disponibili per gli oggetti ThreadedTask.Questo uso di PreparedStatements in una discussione in Java è corretto?

Questo è all'incirca quello che ho finito per scrivere, sta creando un oggetto PreparedStatement per thread come rifiuto? Ho pensato statica PreparedStatments potrebbe creare condizioni di gara ...

versione
 
Thread A stmt.setInt(); 
Thread B stmt.setInt(); 
Thread A stmt.execute(); 
Thread B stmt.execute(); 

A's non viene mai execed ..

È questo thread-safe? Creare e distruggere oggetti PreparedStatement che sono sempre gli stessi non è un enorme spreco?

public class ThreadedTask implements runnable { 
    private final PreparedStatement taskCompleteStmt; 

    public ThreadedTask() { 
     //... 
     taskCompleteStmt = Main.db.prepareStatement(...); 
    } 

    public run() { 
     //... 
     taskCompleteStmt.executeUpdate(); 
    } 
} 

public class Main { 
    public static final db = DriverManager.getConnection(...); 
} 
+2

Non archiviare la connessione, ottenere la connessione quando è necessario. Se è necessaria la prestazione di bettr, utilizzare un pool di connessioni. AS Thilo ha detto di seguito non condividere materiale tra thread. –

risposta

16

Credo non sia una buona idea condividere connessioni di database (e istruzioni preparate) tra thread. JDBC non richiede connessioni per essere thread-safe, e mi aspetterei che la maggior parte dei driver non lo sia.

Assegnare a ogni thread la propria connessione (o sincronizzarsi sulla connessione per ogni query, ma che probabilmente vanifica lo scopo di avere più thread).

La creazione e la distruzione di oggetti PreparedStatement che sono sempre gli stessi non rappresentano un enorme spreco?

Non proprio. La maggior parte del lavoro avviene sul server e verrà memorizzata nella cache e riutilizzata lì se si utilizza la stessa istruzione SQL. Alcuni driver JDBC supportano anche il caching delle istruzioni, in modo che anche l'handle dell'istruzione lato client possa essere riutilizzato.

Si potrebbe notare un miglioramento sostanziale utilizzando query batch invece di (o in aggiunta a) thread multipli. Preparare la query una volta e eseguirla per un sacco di dati in un unico grande batch.

3

È consigliabile utilizzare un pool di connessioni e ottenere ogni thread per richiedere una connessione dal pool. Crea le tue dichiarazioni sulla connessione che ti viene consegnata, ricordandoti di chiuderla e quindi rilasciarla nuovamente alla piscina quando hai finito. Il vantaggio dell'utilizzo del pool è che è possibile aumentare facilmente il numero di connessioni disponibili nel caso in cui la concorrenza di thread stia diventando un problema.

6

Il threadsafety non è il problema qui. Tutto sembra sintatticamente e funzionalmente buono e dovrebbe funzionare per circa mezz'ora. La perdita di risorse è tuttavia il vero problema qui. L'applicazione si bloccherà dopo circa mezz'ora perché non si chiudono mai dopo l'uso. Il database a sua volta prima o poi chiuderà la connessione stessa in modo che possa rivendicarla.

Detto questo, non è necessario preoccuparsi della memorizzazione nella cache delle dichiarazioni preparate. Il driver JDBC e il DB si prenderanno cura di questa attività. Piuttosto preoccuparsi di perdite di risorse e rendere il vostro codice JDBC più solido possibile.

public class ThreadedTask implements runnable { 
    public run() { 
     Connection connection = null; 
     Statement statement = null; 
     try { 
      connection = DriverManager.getConnection(url); 
      statement = connection.prepareStatement(sql); 
      // ... 
     } catch (SQLException e) { 
      // Handle? 
     } finally { 
      if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {} 
      if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {} 
     } 
    } 
} 

Per migliorare il collegamento prestazioni, fanno uso di un pool di connessioni come c3p0 (questo tra l'altro non significa che si può cambiare il modo in cui si scrive il codice JDBC; acquisire sempre e chiudere le risorse in l'intervallo più breve possibile in un blocco try-finally).

+1

Guarda DBUtils Apache Commons per un involucro leggero che si prende cura di tutto il try/catching. – Thilo

+0

Possiamo anche solo usare JPA. Più conveniente non può essere. – BalusC

+0

Se stai usando Java 7+: preferisci usare "prova con i blocchi di risorse". In tal caso non puoi dimenticare di chiudere la connessione e la dichiarazione. –

Problemi correlati