¿Es seguro utilizar una instancia estática de java.sql.Connection en un sistema multiproceso?
Estoy ejecutando una aplicación web en Tomcat. Tengo una clase que maneja todas las consultas de base de datos. Esta clase contiene el Connection
objeto y los métodos que devuelven los resultados de la consulta.
Este es el objeto de conexión:
private static Connection conn = null;
Tiene una sola instancia (singleton).
Además, tengo métodos que ejecutan consultas, como buscar un usuario en la base de datos:
public static ResultSet searchUser(String user, String pass) throws SQLException
Este método utiliza el Connection
objeto estático. Mi pregunta es, ¿es Connection
seguro mi uso en subprocesos de objetos estáticos? ¿O puede causar problemas cuando muchos usuarios llamen al searchUser
método?
¿Es seguro mi uso en subprocesos de objetos de conexión estáticos?
¡Absolutamente no!
De esta manera, la conexión se compartirá entre todas las solicitudes enviadas por todos los usuarios y, por lo tanto, todas las consultas interferirán entre sí. Pero la seguridad de los subprocesos no es su único problema, la fuga de recursos también es el otro problema. Mantienes una única conexión abierta durante toda la vida útil de la aplicación. La base de datos promedio recuperará la conexión cada vez que haya estado abierta durante demasiado tiempo, lo que suele oscilar entre 30 minutos y 8 horas, según la configuración de la base de datos. Entonces, si su aplicación web se ejecuta durante más tiempo, la conexión se perderá y ya no podrá ejecutar consultas.
Este problema también se aplica cuando esos recursos se mantienen como una static
variable que no es de instancia de una instancia de clase que se reutiliza varias veces.
Siempre debes adquirir y cerrar la conexión, la declaración y el conjunto de resultados en el alcance más corto posible , preferiblemente dentro del mismo try-with-resources
bloque donde estás ejecutando la consulta de acuerdo con el siguiente modismo 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;
}
Tenga en cuenta que no debe devolver un ResultSet
aquí. Debe leerlo inmediatamente y asignarlo a una clase que no sea JDBC y luego devolverlo, para que pueda ResultSet
cerrarse de forma segura.
Si aún no está en Java 7, utilice un try-finally
bloque en el que cierre manualmente los recursos que se pueden cerrar en el orden inverso al que los adquirió. Puede encontrar un ejemplo aquí: ¿ Con qué frecuencia se deben cerrar Connection, Statement y ResultSet en JDBC?
Si le preocupa el rendimiento de la conexión, entonces debería utilizar la agrupación de conexiones. Esto está integrado en muchos servidores de aplicaciones Java EE e incluso los contenedores de servlet básicos como Tomcat lo admiten. Simplemente cree una fuente de datos JNDI en el servidor y deje que su aplicación web la obtenga como archivo DataSource
. De forma transparente ya es un grupo de conexiones. Puede encontrar un ejemplo en el primer enlace de la lista a continuación.
Ver también:
- ¿Cómo debo conectarme a la base de datos/fuente de datos JDBC en una aplicación basada en servlet?
- Cuando mi aplicación pierde la conexión, ¿cómo debo recuperarla?
- ¿Estoy utilizando la agrupación de conexiones JDBC?
- Muestre JDBC ResultSet en HTML en la página JSP usando el patrón MVC y DAO
- Tutorial DAO con JDBC
Si solo está ejecutando Select
consultas ( searchUser
parece que solo selecciona datos), no habrá problemas, aparte de la contención del hilo.
Hasta donde yo sé, a Connection
solo puede manejar una consulta a la vez, por lo que al usar una sola instancia esencialmente serializarás el acceso a la base de datos. Pero esto no significa necesariamente que siempre sea seguro acceder a una base de datos como esta en un entorno de subprocesos múltiples. Es posible que aún haya problemas si los accesos simultáneos se entrelazan.