Existen muchas maneras de gestionar el acceso a bases de datos desde ASP.NET, unos mejores que otros, y sin duda cada uno tenemos nuestro propio sistema (“Cada maestrillo tiene su librillo“, como siempre me han dicho en mi casa). ¿Cuál creeis que puede ser el mejor?
Por supuesto a la hora de elegir el sistema más apropiado tendremos que tener en cuenta toda una serie de factores, ventajas y desventajas, de cada uno de los diferentes modos existentes:
- Gestión centralizada :: las conexiones a la base de datos son administradas en una clase común accesible desde cualquier punto de la aplicación (ahorro de recursos a la hora de abrir y cerrar conexiones y realizar consultas ligeras o atómicas.
- Gestión individual :: abrir y cerrar la conexión cada vez que sea necesario lanzar comandos hacia la base de datos.
Desde un punto de vista organizativo, no hay duda que la centralización es la mejor opción: atomización del control de base de datos, administración localizada en un punto de todo el tráfico de datos, y disminución de la complejidad del código. Ahora bien, el diseño de un sistema que permita este tipo de trabajo, aunque no imposible, es relativamente complicado: debemos tener en cuenta que toda aplicación web, al menos en la mayor parte de los casos, deberá soportar un cierto grado de concurrencia de usuarios de manera simultánea, por lo que podemos descartar el uso de variables static (o shared en VisualBasic), ya que estas son compartidas en todas las instancias de la aplicación web en ejecución.
Analicemos la posible solución como conexión común en una variable static:
class ClaseComun { private static SqlConnection __connection; }
Vemos que definimos una clase que contiene la variable privada estática que almacena una conexión de tipo SqlConnection (proveedor de conexión para SQL Server integrado en Microsoft .NET). Vamos a añadir una propiedad a la clase:
public static SqlConnection Connection
{
get { if (__connection == null) { __connection = new SqlConnection(connection_string); __connection.Open(); }
}
Como podemos apreciar, la propiedad creada es de solo lectura: queremos que la conexión quede solo definida por el interior de nuestra clase, aislandola del resto de la aplicación.
Por el momento, todo parece correcto, especialmente para aquellos que estén familiarizados con aplicaciones basadas en Windows Forms, donde este tipo de trabajo es oportuno y francamente útil.
El problema viene cuando lo utilizamos en una aplicación ASP.NET: imaginemos un usuario que entra por primera vez en la página. Al realizar su petición al servidor, ésta será ejecutada, y de no existir una instancia para la variable estática, se creará un objeto SqlConnection y se abrirá la conexión con la base de datos SQL Server.
Ahora bien… Otro usuario, casi de manera simultánea pero unos microsegundos después, solicita al servidor otro acceso. El código ASP.NET, volverá a comprobar la existencia de la variable de conexión, que ya estará instanciada y por tanto no realizará ninguna otra gestión sobre la conexión. Ahora bien… el código ejecutará sus consecuentes peticiones de datos y… ¡peligro! Dos usuarios están usando la misma conexión con la base de datos.
Pese a ser un modo bastante elegante de centralizar la gestión de conexiones, es mortalmente peligroso para aplicaciones web concurrentes. Por lo tanto, pasaremos a la siguiente opción.
Aunque pueda parecer una opción menos eficiente frente a la anterior, la mejor opción bajo mi punto de vista es crear una instancia de la conexión SqlConnection para cada consulta que vayamos a realizar, la abramos, ejecutemos la petición a la base de datos, y luego la cerremos:
SqlConnection cnx = new SqlConnection(connection_string);
cnx.Open();
SqlCommand cmd = new SqlCommand(“SELECT COUNT(*) FROM table_of_clients”, cnx);
object obj = cmd.ExecuteScalar();
/* … */
cnx.Close();
Como vemos, estamos creando una instancia de la conexión para realizar una consulta por lo demás simple, que se abre y se cierra para lanzar la petición a la base de datos. Puede parecer redundante y una pérdida letal de recursos, con una inclusión indiscriminada de líneas extra en el código fuente de nuestra aplicación.
Pero, en el caso de una aplicación web de cierta complejidad donde deban lanzarse varias consultas en una misma petición del usuario al servidor web, ¿es una buena práctica abrir y cerrar la conexión tantas veces? ¿es eficiente?
La respuesta es si. Gracias a las capacidades de connection pooling de ASP.NET y SQL Server ganaremos en eficacia y calidad sin perder recursos por el camino. ¿En qué consiste el connection pooling? Lo explicaré en el próximo post de mi blog, donde podreis comprobar su funcionamiento con algunos ejemplos sencillos que espero os sean de utilidad.
Una cosa os aseguro: ganareis, de lejos, numerosas ventajas frente a otros métodos tradicionales de trabajo.