È sicuro utilizzare un’istanza java.sql.Connection statica in un sistema con multithreading?

Sto eseguendo un’applicazione web su Tomcat. Ho una class che gestisce tutte le query DB. Questa class contiene l’object Connection e i metodi che restituiscono i risultati della query.

Questo è l’object di connessione:

 private static Connection conn = null; 

Ha solo un’istanza (singleton).

Inoltre, ho metodi che eseguono query, come la ricerca di un utente nel db:

 public static ResultSet searchUser(String user, String pass) throws SQLException 

Questo metodo utilizza l’object Connection statica. La mia domanda è, è il mio uso in thread di Connection object statico sicuro? Oppure può causare problemi quando molti utenti chiamano il metodo searchUser ?

il mio uso in thread di collegamento di oggetti statici è sicuro?

Assolutamente no!

In questo modo la connessione verrà condivisa tra tutte le richieste inviate da tutti gli utenti e quindi tutte le query interferiranno l’una con l’altra. Ma il threadsafety non è il tuo unico problema, la perdita di risorse è anche l’altro tuo problema. Stai mantenendo aperta una singola connessione durante tutta la vita dell’applicazione. Il database medio recupererà la connessione ogni volta che è stata aperta per troppo tempo, che di solito è tra 30 minuti e 8 ore, a seconda della configurazione del DB. Pertanto, se la tua applicazione web viene eseguita più a lungo, la connessione viene persa e non sarai più in grado di eseguire query.

Questo problema si applica anche quando tali risorse vengono considerate come una variabile di istanza non static un’istanza di class che viene riutilizzata più volte.

Dovresti sempre acquisire e chiudere la connessione, l’istruzione e il set di risultati nel più breve ambito ansible , preferibilmente all’interno dello stesso blocco try-with-resources come dove stai eseguendo la query secondo il seguente idioma JDBC:

 public User find(String username, String password) throws SQLException { User user = null; try ( Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT id, username, email FROM user WHERE username=? AND password=md5(?)"); ) { statement.setString(1, username); statement.setString(2, password); try (ResultSet resultSet = statement.executeQuery()) { if (resultSet.next()) { user = new User(); user.setId(resultSet.getLong("id")); user.setUsername(resultSet.getString("username")); user.setEmail(resultSet.getString("email")); } } } return user; } 

Notare che non si dovrebbe restituire un ResultSet qui. Se non si è ancora su Java 7, utilizzare un blocco try-finally cui si chiudono manualmente le risorse chiudibili nell’ordine inverso al momento dell’acquisto.

Se ti preoccupi di colbind le prestazioni, dovresti utilizzare invece il pool di connessioni. Questo è integrato in molti server applicativi Java EE e persino portacontatti barebone come Tomcat lo supporta. Basta creare un’origine dati JNDI nel server stesso e lasciare che la tua webapp lo DataSource come DataSource . È in modo trasparente già un pool di connessioni.

Guarda anche:

  • Come devo connettermi al database JDBC / origine dati in un’applicazione basata su servlet?
  • Quando la mia app perde la connessione, come devo recuperarla?
  • Sto usando il pool di connessioni JDBC?
  • Mostra JDBC ResultSet in HTML nella pagina JSP usando pattern MVC e DAO
  • Tutorial DAO con JDBC

Se stai eseguendo solo le query Select ( searchUser suona come se fosse solo la selezione dei dati) non ci saranno problemi, a parte la contesa del thread.

Per quanto ne so, una Connection può gestire solo una query alla volta, quindi utilizzando una singola istanza sarà essenzialmente serializzato l’accesso al database. Ma questo non significa necessariamente, è sempre sicuro accedere a un database come questo in un ambiente multi-thread. Potrebbero esserci ancora problemi se gli accessi concorrenti sono interleaving.